【问题标题】:'Wide character in subroutine entry" - UTF-8 encoded cyrillic words as sequence of bytes'子程序条目中的宽字符' - UTF-8 编码的西里尔字母作为字节序列
【发布时间】:2015-11-23 23:50:25
【问题描述】:

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

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

【问题讨论】:

    标签: perl unicode utf-8 md5 cyrillic


    【解决方案1】:

    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";
    

    【讨论】:

    • 感谢md5_hex() 确实导致了崩溃。我在perldoc Digest::MD5 中忽略了那部分
    • 完美!我对西里尔文(和其他)字母的base64转换有类似的问题,除了拉丁文。我刚刚添加了它,它就像一个魅力!谢谢你和@AlexanderFarber!
    【解决方案2】:

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

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

    您可以使用open 杂注来解决此问题。而不是所有的binmode 语句,使用

    use open qw/ :std :encoding(utf8) /;
    

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

    【讨论】:

      【解决方案3】:

      如果你使用 Mojolicious,那么将 to_json 替换为 encode_json 即可解决问题。

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

      【讨论】:

        【解决方案4】:

        如果您使用 perl 5.0 及更高版本,则可以通过将 to_json 更改为 encode_json 来解决此问题

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-08
          • 2019-08-28
          • 2014-09-11
          • 1970-01-01
          • 2012-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多