Як я можу вивести UTF-8 з Perl?


110

Я намагаюся написати сценарій Perl за допомогою прагми "utf8", і я отримую несподівані результати. Я використовую Mac OS X 10.5 (Leopard), і я редагую TextMate. Усі мої налаштування як для мого редактора, так і для операційної системи за замовчуванням записують файли у форматі utf-8.

Однак, коли я ввожу наступне у текстовий файл, зберігаю його як ".pl" та виконую його, я отримую дружній "алмаз зі знаком питання" замість символів, що не належать до ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

my $str = 'Çirçös';
print( "$str\n" );

Будь-яка ідея, що я роблю неправильно? Я очікую отримати "'irçös" на виході, але я отримаю " ir s" замість цього.


1
Можливо, це не програма .. Я думаю, що це ваша оболонка, чи ваш редактор, який робить вихід
n00ki3

Усі відповіді правильно відповідають на ваше запитання, як явно встановити його на UTF8. Я думаю, вам слід відрегулювати параметри місцевості свого терміналу, як показано в stackoverflow.com/a/14405949/498634 . Термінал не може бути встановлений на UTF8, і тоді дані, записані на STDOUT в UTF8, будуть закодовані неправильно !
Даніель

Відповіді:


160

use utf8;не вмикає вихід Unicode - це дозволяє вводити Unicode у вашій програмі. Додайте це до програми перед print()заявою:

binmode(STDOUT, ":utf8");

Подивіться, чи це допомагає. Це повинно зробити STDOUTвихід у UTF-8 замість звичайного ASCII.


Я не знав про це (я лише вкладав UTF8 в базу даних, ніколи не друкував). +1.
Пол Томблін

1
Ласкаво просимо. Дивіться також ще одну правильну відповідь: stackoverflow.com/questions/627661/writing-perl-code-in-utf8 / ... і пам'ятайте, TMTOWTDI. І @Paul - якщо ви пишете UTF-8 у файл, ви, ймовірно, повинні використовувати binmode () на цьому файловому блоці і зробити його "належним" UTF-8, але якщо він працює ..
Кріс Лутз,

1
інші способи: відкрита прагма ( search.cpan.org/perldoc/open ), перемикач -C ( perldoc.perl.org/perlrun.html#-C )
ysth

1
FWIW тут є причиною: рядки, що містять лише символи latin1 (ISO-8859-1), незважаючи на те, що вони зберігаються більше або менше у utf8, будуть виведені як Latin1 за замовчуванням. Таким чином, сценарії з епохи перед унікодом як і раніше працюють однаково, навіть із перламутровим знанням.
mirod

3
Прагма utf8 не дозволяє вам писати своє джерело в UNICODE, це змушує зрозуміти ваше джерело в кодуванні UTF-8 (або UTF-EBCDIC) коду UNICODE, важлива відмінність.
Час. Овенс

83

Можна використовувати відкриту прагму .

Наприклад, наприклад. нижче встановлено STDOUT, STDIN & STDERR для використання UTF-8 ....

use open qw/:std :utf8/;

1
До речі ... я дав +1. Я думаю, що binmode (STDOUT, ': utf8'), мабуть, більш правильний у цій ситуації. "use open" має й інші корисні способи, але я не можу знайти, як ви можете встановити його, щоб просто кодувати STDOUT?
draegtun

66

TMTOWTDI обрав метод, який найкраще підходить для вашої роботи. Я використовую метод оточення, тому мені не доводиться думати про це.

У навколишньому середовищі :

export PERL_UNICODE=SDL

у командному рядку :

perl -CSDL -le 'print "\x{1815}"';

або з binmode :

binmode(STDOUT, ":utf8");          #treat as if it is UTF-8
binmode(STDIN, ":encoding(utf8)"); #actually check if it is UTF-8

або з PerlIO :

open my $fh, ">:utf8", $filename
    or die "could not open $filename: $!\n";

open my $fh, "<:encoding(utf-8)", $filename
    or die "could not open $filename: $!\n";

або з відкритою прагмою :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";

1
+1 за вичерпну відповідь; зауважте, що SDLмається на увазі як із, так -Cі з PERL_UNICODE. use open ':locale'Прагма також варто згадати, тому що це в сценарії еквівалент -Cі export PER_UNICODE=. Будь-який із цих 3 надасть вам підтримку UTF8 для всіх вхідних та вихідних потоків (будь-які файли чи stdin / stdout / stderr), якщо припустити, що локальне середовище базується на UTF8. Нарешті, щоб також трактувати вихідний код як UTF8, використовуйте use utf8;прагму.
mklement0

perl -Mutf8 -CSDL -e '...'дозволяє споживати / виводити UTF-8 , а також використовувати UTF-8 літерали всередині, -eнаприклад, для папки справи perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
бідолахи


0

Дякую, нарешті знайшли рішення не ставити utf8 :: кодувати весь код. Для синтезу та завершення інших випадків, таких як запис та читання файлів у utf8, а також працює з LoadFile файлу YAML у utf8

use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");

open(FH, ">test.txt"); 
print FH "something éá";

use YAML qw(LoadFile Dump);
my $PUBS = LoadFile("cache.yaml");
my $f = "2917";
my $ref = $PUBS->{$f};
print "$f \"".$ref->{name}."\" ". $ref->{primary_uri}." ";

де cache.yaml:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml

-3

зробіть у своїй оболонці: $ env | grep LANG

Це, ймовірно, покаже, що ваша оболонка не використовує локал utf-8.


Насправді він був встановлений на utf-8. Проблема полягала в тому, що я виводив на STDOUT без встановлення binmode на utf-8;

2
Це було б ортогональним питанням. Вам потрібен ваш скрипт Perl для виведення правильних даних, перш ніж ви можете турбуватися про те, як ваш емулятор терміналу інтерпретує їх.
jrockway
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.