"Широкий символ в записи подпрограммы" - кириллические слова в кодировке UTF-8 как последовательность байтов
Я работаю над игрой слов в Android с большим словарем -
Слова (более 700 000) хранятся в виде отдельных строк в текстовом файле (а затем помещаются в базу данных SQLite).
Чтобы конкуренты не могли извлечь мой словарь, я бы хотел закодировать все слова длиной более 3 символов с помощью md5. (Я не запутываю короткие слова и слова редкими русскими буквами ъ
а также э
потому что я хотел бы перечислить их в моем приложении).
Итак, вот мой скрипт, который я пытаюсь запустить с Perl v5.18.2 на Mac Yosemite:
#!/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
}
Как вы можете видеть, я должен использовать буквы кириллицы в исходном коде моего скрипта Perl - вот почему я поставил use utf8;
на его вершине.
Однако моя настоящая проблема заключается в том, что length($_)
сообщает о слишком высоких значениях (вероятно, сообщает количество байтов вместо количества символов).
Итак, я попытался добавить:
binmode(STDOUT, ":raw");
или же:
binmode(STDOUT, ":utf8");
Но сценарий затем умирает с широким символом в записи подпрограммы в строке с print md5_hex($_)
,
Пожалуйста, помогите мне исправить мой сценарий.
Я запускаю это как:
perl ./generate-md5.pl < words.txt > encoded.txt
и вот пример данных words.txt для вашего удобства:
а
аб
абв
абвг
абвгд
съемка
4 ответа
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";
Моя настоящая проблема в том, что длина ($_) сообщает о слишком высоких значениях
Да, вы читаете из ARGV
дескриптор файла и не установил его кодировку в UTF-8
Вы можете использовать open
Прагма, чтобы исправить это. Вместо всех ваших 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