Строки UTF8 частично не распознаются

Когда я извлекаю кириллический текст из базы данных SQLite3, в некоторых случаях perl (или Mojolicious, или DBIx::Class - я, честно говоря, не знаю) не может декодировать байтовый поток. Например, учитывая текст:

1984г1ф!!11четыре

вывод будет:

1984г1ф!!11������
1984\x{433}1\x{444}!!11\x{fffd}\x{fffd}\x{fffd}\x{fffd}\x{fffd}\x{fffd}

Почему это происходит? Как это исправить?

Обновление: мне удалось отследить источник этой проблемы. Похоже, что искаженная строка берется из пользовательского ввода на веб-странице и отправляется в действие контроллера в качестве параметра: код здесь.

Выполнение действия сохранения создает следующий журнал:

[2012/07/24 14:06:09] [DEBUG] 15703 Mojolicious.Plugin.RequestTimer - POST /admin/node/save (Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1).
[2012/07/24 14:06:09] [DEBUG] 15703 Mojolicious.Routes - Routing to a callback.
[2012/07/24 14:06:09] [DEBUG] 15703 Mojolicious.Routes - Routing to controller "MyApp::Admin" and action "save".
Wide character in print at /home/nikita/perl5/lib/perl5/Log/Log4perl/Appender/File.pm line 245.
Wide character in print at /home/nikita/perl5/lib/perl5/Log/Log4perl/Appender/Screen.pm line 39.
[2012/07/24 14:06:09] [DEBUG] 15703 MyApp.Admin - 123123!!!11������������������

Обновление 2: я использую Morbo в качестве сервера разработки, и макет моего приложения содержит заголовок meta:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

Обновление 3: странно, но иногда строка кодируется и отображается правильно:

[2012/07/24 14:55:52] [DEBUG] 16451 Mojolicious.Routes - Routing to a callback.
[2012/07/24 14:55:52] [DEBUG] 16451 Mojolicious.Routes - Routing to controller "MyApp::Admin" and action "save".
[2012/07/24 14:55:52] [DEBUG] 16451 MyApp.Admin - 112!!ЫВафывафывп
[2012/07/24 14:55:52] [DEBUG] 16451 Mojolicious.Plugin.RequestTimer - 302 Found (0.326543s, 3.062/s).
[2012/07/24 14:55:52] [DEBUG] 16451 Mojolicious.Plugin.RequestTimer - GET /admin (Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1).

и если я сделаю то же самое во второй раз, я получу:

[2012/07/24 14:57:30] [DEBUG] 16451 Mojolicious.Routes - Routing to controller "MyApp::Admin" and action "save".
Wide character in print at /home/nikita/perl5/lib/perl5/Log/Log4perl/Appender/File.pm line 245.
Wide character in print at /home/nikita/perl5/lib/perl5/Log/Log4perl/Appender/Screen.pm line 39.
[2012/07/24 14:57:30] [DEBUG] 16451 MyApp.Admin - 112!!��������������������
[2012/07/24 14:57:30] [DEBUG] 16451 Mojolicious.Plugin.RequestTimer - 302 Found (0.362417s, 2.759/s).
[2012/07/24 14:57:30] [DEBUG] 16451 Mojolicious.Plugin.RequestTimer - GET /admin (Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:14.0) Gecko/20100101 Firefox/14.0.1).

person Nikita Dubrovin    schedule 24.07.2012    source источник
comment
Покажите свой код, чтобы мы могли воспроизведите проблему.   -  person daxim    schedule 24.07.2012
comment
Какой код вам нужен? Слишком много потенциальных точек отказа.   -  person Nikita Dubrovin    schedule 24.07.2012
comment
Создайте минимальный тестовый пример. Если вы плохой программист и не можете этого сделать, предоставьте все: весь ваш код и примеры данных для запуска кода. - UTF-8 в SQLite/DBIC отлично работает для меня.   -  person daxim    schedule 24.07.2012
comment
Смотрите обновление вопроса.   -  person Nikita Dubrovin    schedule 24.07.2012
comment
Правильно ли настроены ваша веб-страница и сервер? Проверьте, что кодировка указана как в заголовке, так и в теге meta.   -  person choroba    schedule 24.07.2012
comment
Почему вы не показываете нам свой код?   -  person Dave Cross    schedule 24.07.2012


Ответы (2)


Предупреждение «широкий символ в печати» заставляет меня думать, что ваш дескриптор выходного файла не ожидает увидеть символы utf-8.

Страница руководства perldiag более подробно объясняет ошибки и предупреждения Perl. Вот что говорится об этом предупреждении.

Широкий символ в %s

(S utf8) Perl встретил расширенный символ (>255), когда он этого не ожидал. Это предупреждение по умолчанию включено для операций ввода-вывода (например, для печати). Самый простой способ отключить это предупреждение — просто добавить к выходным данным слой :utf8, например binmode STDOUT, ':utf8' . Другой способ отключить предупреждение — добавить никаких предупреждений 'utf8'; но это часто ближе к обману. В общем, вы должны явно пометить дескриптор файла кодировкой, см. open и binmode.

Я подозреваю, что вам также было бы полезно прочитать учебник Perl Unicode (и главу 6 4-е издание книги Camel).

person Dave Cross    schedule 24.07.2012
comment
Я не думаю, что это актуально: эти предупреждения создаются приложениями Log4perl. - person Nikita Dubrovin; 24.07.2012
comment
Вы можете быть правы. Но это указывает на то, что у вас есть данные utf-8 где-то в вашей системе. Попробуйте указать приложениям ожидать данные utf-8 и посмотреть, что изменится. А остальные мои советы остаются в силе. При работе с данными utf-8 вы можете многое сделать неправильно. Прочтите документацию. - person Dave Cross; 24.07.2012
comment
Я снова просмотрел свои шаблоны и нашел «% use utf8;». Удаление решило проблему. - person Nikita Dubrovin; 24.07.2012

Удаленный

% use utf8;

из одного из шаблонов, и после этого текст отображается как надо.

person Nikita Dubrovin    schedule 24.07.2012