[Moscow.pm] кодировка в Perl почему все это так странно работает?

Victor Efimov victor на vsespb.ru
Вт Сен 23 11:17:35 PDT 2014


23 сентября 2014 г., 14:05 пользователь Илья Винокуров <ilvin на mail.ru> написал:
> Здравствуйте, Виктор!
>
> Убедил. (Прошу разрешения называть вас на "ты") Теперь я буду говорить так:

ok

>
> Строки в Perl существуют во внутреннем формате, который называется utf8.

не, оно не называется utf8. соотношение такое;
utf8 - кодировка.
UTF-8 кодировка.
внутренний формат строк - если UTF-8 флаг установлен, то данные в
пемяти там скорее в utf8 чем в UTF-8. (это по ссылке было как бы в
шуточной форме "Okay, if you insist"..)

различия с твоей формулировкой:

- не всё что называется utf8 является внутренним форматом строк. utf8
может быть просто кодировка.
- даже если вот у нас есть строка, с UTF-8 флагом, в которой текст.. в
этой кодировке UTF8 (ой, прошу прощения - utf8). то это вовсе не utf8.
потому что у этой строки UTF8 флаг.
в частности она не равна строке без UTF8 флага, но в которой те же
байты в памяти (если это не чистый ASCII)
- внутренний формат может быть вовсе не UTF8/utf8 - ( по той же ссылке
есть "When it's not some other encoding" ), Так вот, он может быть
Latin1.
текст в котором только символы из Latin1 может находиться в двух
разных форматах. между ними ковертируют операциями utf8::downgrade
utf8::upgrade. И если после utf8::downgrade
он находится в формате Latin1 он полностю эквивалентен тому же тексту,
который в utf8 (после utf8::upgrade). эквивалентен значит perl "eq"
оператор говорит что это одни и те же строки, и они равны
во всех смыслах и ведут себя одинаково.


>
> Все данные в Perl поступают в бинарном виде, т.е. Perl их интерпретирует
> как набор байтов.

ок.

>
> Чтобы Perl понял, что бинарные данные являются строкой, эти данные нужно
> декодировать с помощью Encode::decode('UTF-8', $bin).

"Чтобы Perl понял, что бинарные данные являются текстовой строкой" - так лучше.

>
> Чтобы вывести строки из Perl, их нужно закодировать в бинарный вид так:
> Encode::encode('UTF-8', $str)
>

да.

> Теперь у меня все в порядке с терминологией?
>

почти!

> С почтением,
>   Илья Винокуров.
>
>
> Tue, 23 Sep 2014 13:19:49 +0400 от Victor Efimov <victor на vsespb.ru>:
>
> 23 сентября 2014 г., 12:48 пользователь Илья Винокуров <ilvin на mail.ru>
> написал:
>> Здравствуйте, Виктор.
>>
>> Терминология действительно сильно упрощенная, так как
>> внутреннее представление строки Perl проще назвать еще одной кодировкой,
>> с которой нужно работать, чем копаться в кишках.
>
> Не согласен. Термин "кодировка" к этому нельзя применять. Когда речь
> идёт о кодировке - речь идёт о бинарных данных (байтах).
> Символы же это не байлы - это элементы, код у которых может быть
> больше 255. Так же в Perl чётко идеологически разграничены операции
> над текстом и над бинарными данными.
> А именно есть операции которые думают что их операнды текст (регэкспы,
> вывод в файл у которго стоит binmode encoding), есть операции которые
> думают что их операнды - байты (вывод в файл где нет binmode encoding,
> функции типа pack). Это всё нельзя уложить в концепцию кодировок.
>
> символы vs байты определены здесь
> http://search.cpan.org/~shay/perl-5.20.1/pod/perlunitut.pod#Text_strings_%28character_strings%29
>
>>
>> Вот попробуй человеку объяснить зачем нужно для строки в UTF-8 кодировке
>> делать Encode::decode('UTF-8', $string). А когда говоришь, что у Perl своя
>> кодировка,
>> так сразу человек начинает правильно перекодировать строки... А без этой
>> абстракции человек лезет флаги строкам устанавливать...
>
> Может новичку это поможет на ранней стадии только потом помешает.
> Если бы концепция про кодировки была верная, можно было бы
> конвертировать между кодировками с помощью Encode::from_to,
> и вообще не понятно API когда делаются две функции
> Encode::decode/encode чтобы конвертировать из/в кодировку.
>
>>
>> И такой ход мыслей у многих людей, так что здесь
>>
>> http://search.cpan.org/~shay/perl-5.20.1/pod/perlunifaq.pod#What%27s_the_difference_between_UTF-8_and_utf8?
>> Плюнули и согласились:
>> Okay, if you insist: the "internal format" is utf8, not UTF-8.
>
>
> Не согласен с интерпретацией этого куска документации.
> На самом деле речь там идёт про что:
>
> 1) Есть кодировка "UTF-8" и "utf8". Когда декодируют первую, принимают
> во внимание то что не все Unicode символы существуют в прикоде. Когда
> декодируют вторую, это игнорируется,
> т.е. вторая используется как "кодек" похожий на UTF-8 для произвольных
> (бинарных !) данных а не текста.
>
> 2) Внутрненний формат строки в perl, когда у ней установлен UTF-8
> флаг, является не строгим вариантом UTF-8, т.е. в ней могут
> содержаться вообще не символы, просто набор чисел закодированных в
> кодек UTF8, не являющийся валидным UTF-8 но с точки зрения перл
> полностью валидным.
>
> например perl -e 'print v100.2000.3000'
>
> v100.2000.3000 - это строка из трёх элементов: 100, 2000 и 3000.
> закодированна этим кодеком. без оглядки на то есть ли в стандарте
> unicode эти символы. так можно закодировать произвольные числа. т.е.
> UTF8
> как бы используется perl не по назначению.
>
> именно поэтому написан этот параграф.
>
>
>
>>
>> С почтением,
>> Илья Винокуров.
>>
>>
>> Mon, 22 Sep 2014 12:58:13 +0400 от Victor Efimov <victor на vsespb.ru>:
>>
>> 22 сентября 2014 г., 12:51 пользователь Илья Винокуров <ilvin на mail.ru>
>> написал:
>>> Здравствуйте, Николай.
>>>
>>> Внутри Perl строки хранятся в кодировке, совместимой с UTF-8. Эта
>>> кодировка
>>> называется utf8.
>>> Когда строки вводятся в Perl, их нужно декодировать из различных
>>> кодировок
>>> в
>>> utf8.
>>> В том числе нужно декодировать UTF-8 в utf8.
>>> Если строку нужно вывести из Perl, то эту строку нужно кодировать в
>>> различные кодировки.
>>> В том числе нужно кодировать utf8 в UTF-8
>>>
>>
>> только тут введена какя-то странная терминология, которой на самом деле
>> нет.
>>
>> В perl строки не храянятся как набор абстрактных символов. Рассуждения
>> про их кодировку лучше присекать на корню.
>> Отличия между utf8 и UTF-8 - вовсе не в этом, а в том что utf-8 более
>> строкая валидация чем utf8.
>>
>> Но в остальном, если в тексте выше заменить "utf8" на "символьная
>> строка", то будет ок.
>>
>>> Этим занимаются функции Encode::encode('UTF-8', $string) и
>>> Encode::decode('UTF-8', $string).
>>>
>>> Text::Iconv - не используйте это, если точно не знаете почему вам нужен
>>> именно этот модуль.
>>>
>>> Концепцию работы с кодировками в Perl я рассказал,
>>> а вот свой скрипт поправить потрудитесь сами пожалуйста...
>>>
>>> PS: Чтобы не возиться в явном виде с перекодированием строк, в перл
>>> используют
>>>
>>> binmode STDIN, ":encoding(console_in)" if -t STDIN;
>>> binmode STDOUT, ":encoding(console_out)" if -t STDOUT;
>>> binmode STDERR, ":encoding(console_out)" if -t STDERR;
>>>
>>> После этого в STDIN/STDOUT можно читать/писать строки в кодировке utf8
>>> без
>>> перекодирования...
>>>
>>> С почтением,
>>> Илья Винокуров.
>>>
>>> Mon, 22 Sep 2014 01:28:15 +0400 от Nikolay Mishin <mi на ya.ru>:
>>>
>>> Привет, MoscowPM,
>>> тут родился вопрос под win7 (юникс могут быть теже странности, не
>>> проверял)
>>>
>>> #!/usr/bin/env perl
>>> use utf8;
>>> use Modern::Perl;
>>> use Encode::Locale;
>>> use Encode qw( decode encode from_to);
>>> use Text::Iconv;
>>> use Encode::Detect::Detector;
>>> use Data::Dumper qw( Dumper );
>>>
>>>
>>> if (-t)
>>> {
>>> binmode(STDIN, ":encoding(console_in)");
>>> binmode(STDOUT, ":encoding(console_out)");
>>> binmode(STDERR, ":encoding(console_out)");
>>> }
>>>
>>> my $lang = shift or die "Usage: $0 What_is_your_language?\n";
>>> my_dump('lang_01',$lang);
>>> my $converter = Text::Iconv->new( "cp1251", "utf-8");
>>> $lang = $converter->convert($lang);
>>> my_dump('lang_02',$lang);
>>> $lang = Encode::decode("utf8",$lang);
>>> my_dump('lang_03',$lang);
>>> my_dump('lang_04_перл',qq{перл});
>>>
>>> $lang =~ /(perl|перл) (?{print "use Perl or die!!\nИспользуй Перл или
>>> умри!!";}) /ix;#русский не мачится, почему?
>>>
>>> sub my_dump
>>> {
>>> my ($name,$var)=@_;
>>> local $Data::Dumper::Useqq = 1;
>>> local $Data::Dumper::Indent = 0;
>>> local $Data::Dumper::Terse = 1;
>>> print(Encode::Detect::Detector::detect(qq{$lang})." ".qq{\$$name }."
>>> dump=".Dumper($var)."\n");
>>> }
>>>
>>> этот же код на гитхабе
>>>
>>>
>>> https://github.com/mishin/presentation/blob/master/100_regex_4_moscow_pm.pl
>>>
>>> моя задача была, чтобы скрипт
>>> perl 100_regex_4_moscow_pm.pl перл
>>> читая из консоли слово "перл" находил его в регексе внутри скрипта
>>>
>>> вопросы:
>>> 1) почему, если в консоле
>>> perl -MEncode::Detect::Detector -E "say
>>> Encode::Detect::Detector::detect(qq{перл})"
>>> у меня кодировка ISO-8859-7
>>> my $converter = Text::Iconv->new( "cp1251", "utf-8");
>>> Text::Iconv ее проглатывает как cp1251 (причем ISO там не проходит) ?
>>>
>>> 2)что происходит со строкой здесь
>>> UTF-8 $lang_02 dump="\320\277\320\265\321\200\320\273"
>>> $lang = Encode::decode("utf8",$lang);
>>> UTF-8 $lang_03 dump="\x{43f}\x{435}\x{440}\x{43b}"
>>> --что такое делает decode?
>>> я так понимаю - он починивает utf8, но что конкретно
>>>
>>> спасибо, хорошей недели!!
>>>
>>>
>>> --
>>> С уважением
>>> Николай Мишин
>>>
>>> --
>>> Moscow.pm mailing list
>>> moscow-pm на pm.org | http://moscow.pm.org
>>>
>>>
>>>
>>> --
>>> Moscow.pm mailing list
>>> moscow-pm на pm.org | http://moscow.pm.org
>>>
>> --
>> Moscow.pm mailing list
>> moscow-pm на pm.org | http://moscow.pm.org
>>
>>
>>
>> --
>> Moscow.pm mailing list
>> moscow-pm на pm.org | http://moscow.pm.org
>>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>
>
>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>


Подробная информация о списке рассылки Moscow-pm