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

Ale*_*ber 7 unicode perl md5 utf-8 cyrillic

我正在开发一个带有大字典的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;

        #print "ORIGINAL WORD $_\tENCODED WORD: ";

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

        print md5_hex($_) . "\n";            # this line crashes
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我必须在我的Perl脚本的源代码中使用西里尔字母 - 这就是为什么我把use utf8;它放在顶部.

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

所以我尝试添加:

binmode(STDOUT, ":raw");
Run Code Online (Sandbox Code Playgroud)

要么:

binmode(STDOUT, ":utf8");
Run Code Online (Sandbox Code Playgroud)

但是脚本随后在子程序条目中以宽字符死亡print md5_hex($_).

请帮我修改我的脚本.

我把它当作:

perl ./generate-md5.pl < words.txt > encoded.txt
Run Code Online (Sandbox Code Playgroud)

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

?
??
???
????
?????
??????
Run Code Online (Sandbox Code Playgroud)

AnF*_*nFi 15

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";
Run Code Online (Sandbox Code Playgroud)


Bor*_*din 5

我真正的问题是 length($_) 报告的值太高

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

您可以使用open编译指示来解决此问题。而不是你所有的binmode陈述,使用

use open qw/ :std :encoding(utf8) /;
Run Code Online (Sandbox Code Playgroud)

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