use strict; use warnings; use Data::Dumper; my $str1 = 'Perlmonks is the best perl community'; my $str2 = 'Perlmonks is one of the best community of perl users'; if ( $str1 eq $str2 ) { print "$str1\n$str2\n"; exit; } my @wl1 = split /\s+/, $str1; my @wl2 = split /\s+/, $str2; my $diff_str1 = ''; my $diff_str2 = ''; my %wc1; my %wc2; foreach my $word (@wl1) { $wc1{$word}++; } foreach my $word (@wl2) { $wc2{$word}++; } while (@wl1 || @wl2) { my $word1 = ''; my $word2 = ''; # being sloppy and not decrementing word counts for new words # since we only use them for moves while (!$wc2{$word1}) { $diff_str1 .= "<$word1> " if $word1; $wc1{$word1}-- if $word1; $word1 = ''; # prevent fall through if this is the last word last if !@wl1; $word1 = shift @wl1; } while (!$wc1{$word2}) { $diff_str2 .= "<$word2> " if $word2; $wc2{$word2}-- if $word2; $word2 = ''; last if !@wl2; $word2 = shift @wl2; } if ( $word1 && $word2 && $word1 eq $word2 ) { $diff_str1 .= $word1 . ' '; # pairing the word from the origional string with it's output $diff_str2 .= $word2 . ' '; # lets us do things like case insensitive, but preserving match later } else { $diff_str1 .= "[$word1] " if $word1; $diff_str2 .= "[$word2] " if $word2; } $wc1{$word2}--; $wc2{$word1}--; } print "$diff_str1\n$diff_str2\n"; #### Perlmonks is the best [perl] [community] Perlmonks is the best [community] [perl] #### $str1 = 'Perlmonks is the best perl perl community'; $str2 = 'Perlmonks is one of the best community of perl users'; --------- Perlmonks is the best [perl] [community] Perlmonks is the best [community] [perl]