LINUX.ORG.RU

Научите utf8 в perl

 


5

1

Использую perl 5.20 в debian 8. Вот такой код:

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use open qw(:utf8 :std);
use Data::Dumper;

print "тест utf8\n";
my @files = glob "Стільниця/*";
push @files, "кирилица для Dumper";
print Dumper @files;

2/0; # Делаем ошибку для проверки utf8 в STDERR

Даёт вот такой результат:
Useless use of division (/) in void context at ./Стільниця/test_utf8.pm line 14.
тест utf8
$VAR1 = 'Стільниця/тест.txt';
$VAR2 = 'Стільниця/test_utf8.pm';
$VAR3 = "\x{43a}\x{438}\x{440}\x{438}\x{43b}\x{438}\x{446}\x{430} \x{434}\x{43b}\x{44f} Dumper";
Illegal division by zero at ./Стільниця/test_utf8.pm line 14.

Как видите нормально прошло только print с строкой utf8, всё остальное ..., ну вы видите. Как заставить perl выводить кирилицу а не кракозябры???
А ещё где-то читал что в perl самая лучшая поддержка юникода. Если это называется «лучшая» то мне страшно представить что творится в других языках.

Ответ на: комментарий от trancefer

Ну если еще добавить binmode STDERR, ":utf8"; то совершенно никаких изменений.

SyntaxError
() автор топика

Попробуй обновиться до 5.22, кажется там поправили взаимодействие с файловой системой в utf-8.

Olegymous ★★★
()

попробуй ради интереса use encoding 'utf8';
оно хоть и устаревшее и выдаёт какой-то там ворнинг, но в каком-то случае, помню, помогло.

Bad_ptr ★★★★★
()

glob возвращает байты. Нужно декодировать (use Encode 'decode';) их из системной кодировки (которая по замечательному совпадению оказалась тоже utf8) из байтов в символы. Для портативного способа сделать это см. Encode::Locale.

AITap ★★★★★
()
Ответ на: комментарий от Olegymous
➜  ~  apt-cache policy perl              
perl:
  Встановлено: 5.20.2-3+deb8u1
  Кандидат:    5.20.2-3+deb8u1
  Таблиця версій:
 *** 5.20.2-3+deb8u1 0
        990 http://ftp.ua.debian.org/debian/ jessie/main i386 Packages
        100 /var/lib/dpkg/status


Как видишь в репозитории нет новее версии. Другие способы установки не предлагать.

SyntaxError
() автор топика
Ответ на: комментарий от Deleted

В английском не очень силён, решения проблемы не нашел. Если можно тыкните носом в код для копипасты.

SyntaxError
() автор топика
Ответ на: комментарий от bvn13

Ну на дампер можно и забить, но вот на ошибки с кракозябрами никак.

SyntaxError
() автор топика
#!/usr/bin/perl

use utf8;
use strict;
use warnings;
use Data::Dumper;

# укажет что от нас ждут юникодный "выхлоп"
# без этого будут варнинги: Wide character in print
use open qw/:encoding(UTF-8) :std/;

# собственно "выхлоп"
print {*STDOUT} "привет\n";
print {*STDERR} "привет\n";

my @files = glob './*';

# проверяем, скорее всего у кириллических строк (имен файлов)
# не установлен юникодный флаг
printf qq{%s => %s\n}, $_, utf8::is_utf8($_) for @files;
print {*STDOUT} Dumper \@files;

# теперь надо явно поднять юникодный флаг для элементов массива
@files = map { utf8::decode($_); $_ } @files;

# проверяем еще раз
printf qq{%s => %s\n}, $_, utf8::is_utf8($_) for @files;
print {*STDOUT} Dumper \@files;
outtaspace ★★★
()
Последнее исправление: outtaspace (всего исправлений: 3)
Ответ на: комментарий от SyntaxError

Помогло, кроме дампера.

Скорее всего с дампером порядок, если в листинге символы кодируются как \x{43f}, значит что строка во внутреннем представлении Perl.

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

Дампер по прежнему не работает, но что более важно - в сообщениях ошибок кракозябры. По всей видимости проблема в том что перл не понимает что у меня имена файлов в utf8, вот и сыпет ошибки с кракозябрами вместо имен файлов.

SyntaxError
() автор топика
Ответ на: комментарий от SyntaxError

Дампер по прежнему не работает

В чем это выражается?

перл не понимает что у меня имена файлов в utf8

Гм, у меня юникодные терминал и локаль, вот такое:

$locale | head -1
>LANG=ru_RU.UTF-8
$touch привет
$perl -wE 'say for glob q{./*}'
>./привет

Более того:

$perl -MData::Dumper -wE 'say $_, Dumper($_) for glob q{./*}'
>./привет$VAR1 = './привет';

outtaspace ★★★
()
Последнее исправление: outtaspace (всего исправлений: 1)
Ответ на: комментарий от outtaspace

В чем это выражается?

Строка с кирилицей выводится во внутреннем представлении. Читать такое «\x{43a}\x{438}\x{440}\x{438}\x{43b}\x{438}\x{446}\x{430} не возможно

$locale | head -1
LANG=ru_RU.UTF-8
$touch привет
$perl -wE 'say for glob q{./*}'
./привет

А теперь переведи все имена в верхний регистр

$perl -wE 'say uc $_ for glob q{./*}'
Wide character in say at -e line 1.
./привÐΜт

и ты испытаешь боль и мучения.

SyntaxError
() автор топика
Ответ на: комментарий от SyntaxError

не возможно

Зато очень удобно дебажить. Это приоритетно для большинства разработчиков, которые «дампят», сразу ясно что в строке.

и ты испытаешь боль и мучения.

Разве? Просто указываю что и как воспринимать:

$perl -CS -wE 'map { utf8::decode($_); say uc } glob q{./*}'
>./ПРИВЕТ
outtaspace ★★★
()
Ответ на: комментарий от SyntaxError

Читать такое «\x{43a}\x{438}\x{440}\x{438}\x{43b}\x{438}\x{446}\x{430} не возможно

Но ведь всегда есть выход:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $str = qq{\x{43a}\x{438}\x{440}\x{438}\x{43b}\x{438}\x{446}\x{430}};

$Data::Dumper::Useperl = 0;
print Dumper $str;

{
    no warnings 'redefine';
    sub Data::Dumper::qquote {
        my $s = shift;
        return "'$s'";
    }
}

$Data::Dumper::Useperl = 1;
print Dumper $str;

Напечатает:

$perl -CS -w xxx.pl
>$VAR1 = "\x{43a}\x{438}\x{440}\x{438}\x{43b}\x{438}\x{446}\x{430}";
>$VAR1 = 'кирилица';

outtaspace ★★★
()
Ответ на: комментарий от SyntaxError

А как насчёт ошибок

Дык еще проще. Указываем что у нас в коде utf8, указываем что в :std будем отдавать utf8, пишем в STDERR:

$perl -CS -wE 'use utf8; die q{Ошибка}'
>Ошибка at -e line 1.
outtaspace ★★★
()
Ответ на: комментарий от outtaspace

Спасибо за кирилицу в дампере, все работает.
Но вот с ошибками не все так однозначно. Если в пути к скрипту находится кирилица то вывод ошибки, к примеру, будет вот такой

Illegal division by zero at тест.pl line 24.

Как вот эту проблему решить, кроме как не использовать utf или использовать устаревший модуль encoding я не нашел.

SyntaxError
() автор топика
Ответ на: комментарий от SyntaxError

Если в пути к скрипту находится кирилица

Да, это печалька. Причем не только в этом случае. Например $! ($OS_ERROR):

open my $fh, '<', 'тратата' or die q{can't open file: }. $!;

Будет так выглядеть:

$perl тратата.pl
>can't open file: No such file or directory at тратата.pl line 7.
$perl -CS тратата.pl
>can't open file: No such file or directory at ÑÑаÑаÑа.pl line 7.

И такая история много лет, не знаю как правильно такое готовить. Есть подвижки в свежих perldelta:

https://metacpan.org/pod/distribution/perl/pod/perldelta.pod#text-will-be-returned-in-UTF-8-when-appropriate

https://metacpan.org/pod/distribution/perl/pod/perldelta.pod#text-is-now-in-English-outside-the-scope-of-use-locale

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

А так совсем смешно:

#!/usr/bin/perl

use utf8;
use autodie qw(open);

open my $fh, '<', 'тратата';

$perl -CS тратата.pl
>Can't open 'тратата' for reading: 'No such file or directory' at ÑÑаÑаÑа.pl
outtaspace ★★★
()
Ответ на: комментарий от SyntaxError

Чтение deprecated? Посмотри, что он делает и сделай это руками либо нагугли, какие ещё модули так умеют.

x3al ★★★★★
()

Подвожу итог, вот такой код

#!/usr/bin/perl

use strict;
use warnings;
require utf8::all;
binmode(STDERR, ":bytes");
use Data::Dumper;

print "тест utf8\n";
my @files = glob "Стільниця/*";
push @files, "кирилица для Dumper";
print Dumper @files;

print 2/0;

И вот результат
тест utf8
$VAR1 = 'Стільниця/тест.txt';
$VAR2 = 'Стільниця/test_utf8.pm';
$VAR3 = 'кирилица для Dumper';
Illegal division by zero at ./Стільниця/test_utf8.pm line 15.

Как видите все работает как задумано. Насколько хорошее это решения не берусь судить.

SyntaxError
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.