“子程序条目中的宽字符”- UTF-8 编码的西里尔文字作为字节序列

'Wide character in subroutine entry" - UTF-8 encoded cyrillic words as sequence of bytes

我正在用一本大词典做一个 Android 文字游戏 -

单词(超过 700 000 个)作为单独的行保存在文本文件中(然后放入 SQLite 数据库中)。

为了保护我的字典,我想用 md5 对所有超过 3 个字符的单词进行编码。 (我不会用罕见的俄语字母 ъэ 混淆短词和词,因为我想在我的应用程序中列出它们)。

这是我的脚本,我尝试在 Mac Yosemite:

上使用 perl v5.18.2 运行 ]
#!/usr/bin/perl -w

use strict;
use utf8;
use Digest::MD5 qw(md5_hex);

binmode(STDIN, ":utf8");
#binmode(STDOUT, ":raw");
binmode(STDOUT, ":utf8");

while(<>) {
        chomp;
        next if length($_) < 2; # ignore 1 letter junk
        next if /жы/;           # impossible combination in Russian
        next if /шы/;           # impossible combination in Russian

        s/ё/е/g;
    
        if (length($_) <= 3 || /ъ/ || /э/) { # do not obfuscate short words
                print "$_\n";                # and words with rare letters
                next;
        }

        print md5_hex($_) . "\n";            # this line crashes
}

如您所见,我必须在 Perl 脚本的源代码中使用西里尔字母 - 这就是我将 use utf8; 放在其顶部的原因。

但是我真正的问题是 length($_) 报告的值太高(可能报告的是字节数而不是字符数)。

所以我尝试添加:

binmode(STDOUT, ":raw");

或:

binmode(STDOUT, ":utf8");

但是脚本随后在 print md5_hex($_).

行处以 Wide character in subroutine entry 结束

请帮助我修复我的脚本。

我运行它是:

perl ./generate-md5.pl < words.txt > encoded.txt

为了方便起见,这里是示例 words.txt 数据:

а
аб
абв
абвг
абвгд
съемка

md5_hex 需要一个字节字符串作为输入,但您传递的是一个解码字符串(一串 Unicode 代码点)。显式编码字符串。

use strict;
use utf8;
use Digest::MD5;
use Encode;
# ....
# $_ is assumed to be utf8 encoded without check
print Digest::MD5::md5_hex(Encode::encode_utf8($_)),"\n";
# Conversion only when required:
print Digest::MD5::md5_hex(utf8::is_utf8($_) ? Encode::encode_utf8($_) : $_),"\n";

my real problem is that length($_) reports too high values

是的,您正在从 ARGV 文件句柄中读取并且尚未将其编码设置为 UTF-8

您可以使用 open pragma 来解决这个问题。使用

而不是所有 binmode 语句
use open qw/ :std :encoding(utf8) /;

这会将所有文件句柄(包括标准文件句柄)的默认打开模式更改为 :encoding(utf8)

如果你使用 Mojolicious 然后将 to_json 替换为 encode_json 将解决问题。

来自 JSON 模块的文档,to_json 关键字: 如果您想编写与外部世界通信的现代 perl 代码,您应该使用 encode_json(假设 JSON 数据以 UTF-8 编码)。 而且我无法预见那里的非 UTF-8 世界。

如果您使用的是 perl 5.0 及更高版本,则可以通过将 to_json 更改为 encode_json

来解决此问题