Использование 'use utf8;' дает мне "Широкий характер в печати"

86

Если я запустил следующую программу Perl:

perl -e 'use utf8; print "鸡\n";'

Я получаю это предупреждение:

Wide character in print at -e line 1.

Если я запустил эту программу Perl:

perl -e 'print "鸡\n";'

Я не получаю предупреждения.

Я думал, что use utf8необходимо использовать символы UTF-8 в Perl-скрипте. Почему это не работает и как это исправить? Я использую Perl 5.16.2. У меня такая же проблема, если это находится в файле, а не в командной строке.

Эрик Джонсон
источник
3
"Почему это не работает?" Это действительно работает, но по моему опыту работы с Unicode есть много очень неработающих программ, которые выглядят так, как будто они работают. Когда вы исправляете одну вещь, делая код менее ошибочным, результаты кажутся намного хуже. Только когда вы исправите последнюю часть, все снова станет хорошо.
hobbs 04

Ответы:

110

Без use utf8Perl интерпретирует вашу строку как последовательность однобайтовых символов. Как видно из этого, в вашей строке четыре байта:

$ perl -E 'say join ":", map { ord } split //, "鸡\n";'
233:184:161:10

Первые три байта составляют ваш символ, последний - перевод строки.

Вызов to printотправляет эти четыре символа в STDOUT. Затем ваша консоль решает, как отображать эти символы. Если ваша консоль настроена на использование UTF8, она будет интерпретировать эти три байта как ваш единственный символ, и это то, что отображается.

Если мы добавим utf8модуль, все будет иначе. В этом случае Perl интерпретирует вашу строку как всего два символа.

$ perl -Mutf8 -E 'say join ":", map { ord } split //, "鸡\n";'
40481:10

По умолчанию уровень ввода-вывода Perl предполагает, что он работает с однобайтовыми символами. Поэтому, когда вы пытаетесь напечатать многобайтовый символ, Perl думает, что что-то не так, и выдает предупреждение. Как всегда, вы можете получить более подробное объяснение этой ошибки, включив use diagnostics. Он скажет так:

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

Как указывали другие, вам нужно указать Perl, чтобы он принимал многобайтовый вывод. Есть много способов сделать это (см. Некоторые примеры в Perl Unicode Tutorial ). Один из самых простых способов - использовать -CSфлаг командной строки, который сообщает трем стандартным дескрипторам файлов (STDIN, STDOUT и STDERR) работать с UTF8.

$ perl -Mutf8 -e 'print "鸡\n";'
Wide character in print at -e line 1.
鸡

против

$ perl -Mutf8 -CS -e 'print "鸡\n";'

Юникод - это большая и сложная область. Как вы видели, кажется, что многие простые программы поступают правильно, но по неправильным причинам. Когда вы начинаете исправлять часть программы, все становится еще хуже, пока вы не исправите всю программу.

Дэйв Кросс
источник
Как правильно писать, -Mutf8если не в одном лайнере perl?
Лэй Ян
@LeiYang:use utf8;
Дэйв Кросс,
80

Все use utf8;это говорит Perl о том, что исходный код закодирован с использованием UTF-8. Вам нужно указать Perl, как кодировать ваш текст:

use open ':std', ':encoding(UTF-8)';
икегами
источник
Спасибо, это хорошо работает для программ, хранящихся в файлах, в отличие от однострочных команд в командной строке, о которых говорит ответ @DaveCross.
vktec 09
19

Кодируйте весь стандартный вывод как UTF-8:

binmode STDOUT, ":utf8";
Борис Иванов
источник
2
use open ':std', ':encoding(UTF-8)';как предлагается другим ответом, делает это для STDOUT, но также отмечает STDERR и STDIN как UTF-8, поэтому вы получаете три по цене одного оператора. См. Также stackoverflow.com/a/42194059
Стивен Остермиллер,
Согласен. Это даже лучше.
Борис Иванов
14

Вы можете приблизиться к «просто используйте utf8 везде», используя модуль CPAN utf8::all.

perl -Mutf8::all -e 'print "鸡\n";'

Когда он printполучает что-то, что он не может напечатать (символ больше 255, если :encodingслой не предоставлен), он предполагает, что вы хотели кодировать его с помощью UTF-8. Он делает это после предупреждения о проблеме.

Джоэл Бергер
источник
5

Вы можете использовать это,

perl -CS filename.

Это также устранит эту ошибку.

Картикеян Р.С.
источник
только это помогло
muenalan
0

На испанском языке вы можете найти эту ошибку, когда не начнете использовать:

use utf8;

Кодировка вашего редактора имеет другую кодировку. Итак, то, что вы видите в редакторе, не то, что делает Perl. Чтобы решить эту ошибку, просто измените кодировку редактора на Unicode / UTF-8 .

DiegoAr
источник
1
Нет. Ошибка не в этом. Код был правильно закодирован как UTF8, но дескриптор выходного файла не знал об этом.
Дэйв Кросс