Використання '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.03.13

Відповіді:


110

Без use utf8Perl інтерпретує ваш рядок як послідовність однобайтових символів. Як видно з цього, у вашому рядку є чотири байти:

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

Перші три байти складають вашого персонажа, останній - це подача рядків.

Заклик до 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 для деяких прикладів). Одним з найпростіших способів є використання -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

19

Кодувати всі стандартні результати як UTF-8:

binmode STDOUT, ":utf8";

2
use open ':std', ':encoding(UTF-8)';як пропонується іншою відповіддю, це робить для STDOUT, але також позначає STDERR та STDIN як UTF-8, тож ви отримуєте три за ціну одного твердження. Дивіться також stackoverflow.com/a/42194059
Стівен Ostermiller

Погодьтеся. Це ще краще.
Борис Іванов

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 .


1
Ні. Це не те, що спричинило помилку. Код був правильно закодований як UTF8, але вихідний маніпулятор файлу не знав, що він є.
Dave Cross
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.