Как я могу вывести 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», но вместо этого получаю «irirçös».

DDA
источник
1
Может быть, дело не в программе .. я думаю, что это ваша оболочка или редактор, который делает вывод
n00ki3
Все ответы правильно отвечают на ваш вопрос, как явно установить UTF8. Я думаю, вам следует отрегулировать настройки локали вашего терминала, как показано на stackoverflow.com/a/14405949/498634 . Терминал может быть не установлен в UTF8, и тогда данные, записанные в STDOUT в UTF8, будут закодированы неправильно !
Даниэль Бёмер
Отличный ответ, как работать 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. Таким образом, скрипты из эпохи до юникода по-прежнему работают одинаково, даже с perl, поддерживающим юникод.
mirod
3
Прагма utf8 не позволяет вам писать ваш источник в UNICODE, она заставляет понимать ваш источник в кодировке UTF-8 (или UTF-EBCDIC) UNICODE, что является важным отличием.
Час. Owens
83

Вы можете использовать директиву open .

Например, ниже устанавливает STDOUT, STDIN и STDERR для использования UTF-8 ....

use open qw/:std :utf8/;
Draegtun
источник
1
Кстати ... Я поставил u +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";
Чес. Owens
источник
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 :: encode во всем коде. Для синтеза и завершения для других случаев, таких как запись и чтение файлов в 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.

nxadm
источник
На самом деле он был установлен на utf-8. Проблема заключалась в том, что я выводил в STDOUT без установки binmode на utf-8;
2
Это было бы ортогональной проблемой. Вам понадобится ваш Perl-скрипт для вывода правильных данных, прежде чем вы сможете беспокоиться о том, как ваш эмулятор терминала интерпретирует их.
jrockway