在Perl第2卷中查找两个Unicode字符串之间差异的快速方法

时间:2018-12-06 12:32:51

标签: string perl unicode

在同一主题的原始question中,answer既酷又快速,但是更新的Perls不再支持这种用例,它们发出了弃用的警告:

Use of strings with code points over 0xFF as arguments to bitwise xor (^) operator is deprecated

如何在Perl中找到两个unicode字符串之间的差异?

2 个答案:

答案 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位(数据的四倍)是否仍然足够快,或者您根本不关心字符位置是由您决定的。