Implementations check OK. Rate csebe moritz resubst bitwise csebe 81457/s -- -78% -88% -92% moritz 377674/s 364% -- -45% -63% resubst 686400/s 743% 82% -- -33% bitwise 1030128/s 1165% 173% 50% -- #### use Benchmark 'cmpthese'; our $str1 = "12345 ABC 987 MNO"; our $str2 = " CDE"; sub merge_csebe { my( $s1, $s2 ) = map { [ split //, $_ ] } @_; for ( my $i = 0; $i < @$s1; $i++ ) { if( $s2->[$i]) { if( ( $s1->[$i] ne q{ } ) && ( $s2->[$i] eq q{ } ) ) { $s2->[$i] = $s1->[$i]; } } else { $s2->[$i] = $s1->[$i]; } } return join q{}, @$s2; } sub merge_bitwise { my $s2 = $_[1] =~ tr/ /\x{0}/r; return $s2 | $_[0] & ( "\x{ff}" x length $_[0] ^ $s2 =~ tr/\x{00}/\x{FF}/cr ); } sub merge_resubstr { my $s1 = shift; while( $_[0] =~ m/(\S+)/g ) { substr( $s1, pos($_[0])-length($1), length($1) ) = $1; } return $s1; } sub merge_moritz { my $pos = 0; my $res = ''; for my $chunk (split /([^ ]+)/, $_[1]) { if (substr($chunk, 0, 1) eq ' ') { $res .= substr $_[0], $pos, length $chunk; } else { $res .= $chunk; } } continue { $pos += length $chunk; } if ($pos < length $_[0]) { $res .= substr $_[0], $pos; } return $res; } print "Implementations check OK.\n" if( 4 == grep { $_ eq '12345 CDE 987 MNO' } merge_bitwise($str1,$str2), merge_resubstr($str1,$str2), merge_moritz($str1,$str2), merge_csebe($str1,$str2), ); cmpthese ( -5, { bitwise => sub { my $rv = \&merge_bitwise ($main::str1,$main::str2) }, resubst => sub { my $rv = \&merge_resubstr($main::str1,$main::str2) }, moritz => sub { my $rv = \&merge_moritz ($main::str1,$main::str2) }, csebe => sub { my $rv = \&merge_csebe ($main::str1,$main::str2) }, } ); #### # String length is 3515KB. ok 1 - Bitwise ok 2 - Regex/Substr ok 3 - moritz ok 4 - csebe 1..4 Rate csebe moritz resubst bitwise csebe 0.376/s -- -91% -95% -99% moritz 4.11/s 995% -- -46% -94% resubst 7.63/s 1931% 86% -- -89% bitwise 69.1/s 18302% 1581% 806% -- #### use Benchmark 'cmpthese'; use Test::More; use constant DURATION => 20; # seconds. use constant LENGTH => 200000; # repititions of the sample strings. our $str1 = join q{ }, ("12345 ABC 987 MNO") x LENGTH; our $str2 = join q{ }, (" CDE ") x LENGTH; our $want = join q{ }, ("12345 CDE 987 MNO") x LENGTH; diag "String length is ", sprintf( "%d",length($str1)/1024), "KB."; sub merge_csebe { my( $s1, $s2 ) = map { [ split //, $_ ] } @_; for ( my $i = 0; $i < @$s1; $i++ ) { if( $s2->[$i]) { if( ( $s1->[$i] ne q{ } ) && ( $s2->[$i] eq q{ } ) ) { $s2->[$i] = $s1->[$i]; } } else { $s2->[$i] = $s1->[$i]; } } return join q{}, @$s2; } sub merge_bitwise { my $s2 = $_[1] =~ tr/ /\x{0}/r; return $s2 | $_[0] & ( "\x{ff}" x length $_[0] ^ $s2 =~ tr/\x{00}/\x{FF}/cr ); } sub merge_resubstr { my $s1 = shift; while( $_[0] =~ m/(\S+)/g ) { substr( $s1, pos($_[0])-length($1), length($1) ) = $1; } return $s1; } sub merge_moritz { my $pos = 0; my $res = ''; for my $chunk (split /([^ ]+)/, $_[1]) { if (substr($chunk, 0, 1) eq ' ') { $res .= substr $_[0], $pos, length $chunk; } else { $res .= $chunk; } } continue { $pos += length $chunk; } if ($pos < length $_[0]) { $res .= substr $_[0], $pos; } return $res; } is( merge_bitwise ($str1,$str2), $want, "Bitwise" ); is( merge_resubstr($str1,$str2), $want, "Regex/Substr" ); is( merge_moritz ($str1,$str2), $want, "moritz" ); is( merge_csebe ($str1,$str2), $want, "csebe" ); done_testing(); cmpthese ( -DURATION(), { bitwise => sub { my $rv = \&merge_bitwise ($main::str1,$main::str2) }, resubst => sub { my $rv = \&merge_resubstr($main::str1,$main::str2) }, moritz => sub { my $rv = \&merge_moritz ($main::str1,$main::str2) }, csebe => sub { my $rv = \&merge_csebe ($main::str1,$main::str2) }, } );