在同一主题的原始question中,answer既酷又快速,但是更新的Perls不再支持这种用例,它们发出了弃用的警告:
Use of strings with code points over 0xFF as arguments to bitwise xor (^) operator is deprecated
如何在Perl中找到两个unicode字符串之间的差异?
答案 0 :(得分:2)
使用固定宽度编码对字符串进行编码。
my $s1 = encode('UTF-32', $original_string_1);
my $s2 = encode('UTF-32', $original_string_2);
my $mask = $s1 ^ $s2;
while ($mask =~ /\G(?:\0{4})*+(.{4})/sg) {
my $pos = $-[1] / 4;
printf "%d %s %s\n",
$pos,
substr($original_string_1, $pos, 1),
substr($original_string_2, $pos, 1);
}
当然,这仍然存在使用XOR的问题(与替换相反,存在插入和删除问题)。 Algorithm::Diff提供了“重新同步”的功能。
还请注意,并非所有代码点都适合自己打印。控制字符,连续标记和其他代码点可能不应直接打印出来。
答案 1 :(得分:1)
将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位(数据的四倍)是否仍然足够快,或者您根本不关心字符位置是由您决定的。