Кодирование строк Unicode до октетов в кодировке UTF-8 должно работать без предупреждений:
#!perl
use strict;
use warnings;
use Encode 'encode';
use charnames ':full'; # just for the example below
binmode STDOUT, ':encoding(UTF-8)';
sub cmp_unicode {
my ($s1, $s2) = @_;
$s1 = encode( 'UTF-8' => $s1 );
$s2 = encode( 'UTF-8' => $s2 );
my $mask = $s1^$s2;
while ($mask =~ /[^\0]/g) {
print substr($s1,$-[0],1), ' ', substr($s2,$-[0],1), ' ', $-[0], "\n";
}
}
cmp_unicode( 'abc', 'def' );
cmp_unicode( " <\N{SNOWMAN}>", " <\N{FATHER CHRISTMAS}>" );
cmp_unicode( " <\N{LATIN CAPITAL LETTER A WITH DIAERESIS}!!>", " <...>" );
Индексы будут индексами октетов, а не индексами в строках Unicode.Решение @ ikegami по декодированию в UTF-32 намного лучше, так как находит индексы в исходных строках Unicode.Ниже приведен адаптированный пример:
#!perl
use strict;
use warnings;
use Encode 'encode';
use charnames ':full'; # just for the example below
binmode STDOUT, ':encoding(UTF-32)';
sub cmp_unicode {
my ($s1, $s2) = @_;
$s1_32 = encode( 'UTF-32' => $s1 );
$s2_32 = encode( 'UTF-32' => $s2 );
my $mask = $s1_32^$s2_32;
while ($mask =~ /\G(?:\0{4})*+(.{4})/sg) {
printf "%d %s %s\n",
$pos,
substr($s1, $pos, 1),
substr($s2, $pos, 1);
}
}
cmp_unicode( 'abc', 'def' );
cmp_unicode( " <\N{SNOWMAN}>", " <\N{FATHER CHRISTMAS}>" );
cmp_unicode( " <\N{LATIN CAPITAL LETTER A WITH DIAERESIS}!!>", " <...>" );
Является ли обновление до 32-разрядного (в четыре раза больше данных) все еще достаточно быстрым или вас просто не волнует положение символов, решать вам.