Size: a a a

2021 January 22

AP

Anton Petrusevich in Modern::Perl
Oleg Pronin
Я заметил, что многие путаются в utf8 сильно и получают wide character или кракозябры (двойной энкод etc). Хотя тема на самом деле дико простая.
Все что нужно знать:
1) у перла строка может представлять 2 сущности - byte stream и string. is_utf8 говорит какой из режимов включен. В режиме строки просто некоторые функции (substr, lenght И так далее) меняют свой behaviour с побайтового на посимвольный, что занимает дополнительное процессорное время естественно, потому что в пасяти все равно utf8.
2) внутренее представление не изменяется никак при переходе из одного режима в другой. decode_utf8 не делает нихрена кроме как проверяет что там нет инвалидных последовательностей utf8 и переключает режим.
3) чтобы не запутаться где какой режим, простое правило - все что приходит извне (чтение из сокета, файла, stdin, ...) - всегда байтовое. Соответсвенно все что туда отправляется должно быть тоже (иначе будет wide character, однако изза совпадения внутреннего прдставления, все будет работать).
4) еще простое правило - функция is_utf8 за крайне редкими исключениями не должна использоваться. Вы всегда должны знать где у вас байты а где символы. Для этого как правило сразу на входе декодят и в приложении используются символы (кроме случая когда данные бинарные должны быть), и энкодятся в самом конце перед записью в канал.
5) некоторые библиотеки избавляют вас от необходимости энкодить и декодить. Например json::xs::decode_json() ожидает от вас бинарный поток и порождает структуру с символами. А на encode ожидает символы и порождает байты. Обычно это интуитивно логично и ожидаемо.
В случаи работы через обьект JSON::XS->new->utf8->
Метод utf8 как раз заставляет его порождать на декод и ожидать на энкод символы. Если его не писать то в структуре которую вернет декод будут тоже байты (лучше так не делать, только если точно уверены что там только инглиш). Но на вход декод и выход энкод всегда байты, это не меняется, иначе бессмыслица.
Еще например template toolkit аналогично, считывает с диска байты, декодит в символы, ожидает от вас переменные в символах, рендерит и энкодит в байты итоговый результат.
>  чтобы не запутаться где какой режим, простое правило - все что приходит извне (чтение из сокета, файла, stdin, ...) - всегда байтовое.

не всегда. например, дби/дбд, многие умеют автоматически декодить/енкодить ютф8, если при коннекте указать. в итоге, прочитанный джейсон из дб оказывается уже символьной строкой.
источник

OP

Oleg Pronin in Modern::Perl
Это пункт 5)
источник

OP

Oleg Pronin in Modern::Perl
Внутри dbi там где они вычитали всегда байты
источник

AP

Anton Petrusevich in Modern::Perl
я про то, что библиотек может получиться в цепочке больше одной
источник

AP

Anton Petrusevich in Modern::Perl
у мыскуля флаг при коннекте, декод на уровне драйвера
источник

OP

Oleg Pronin in Modern::Perl
Это только маны помогут. Главное всегда понимать где у тебя что, а не is utf8 вставлять везде и бегать от удиаления схерали wide char и крокозябры
источник

AP

Anton Petrusevich in Modern::Perl
когда ты сам пишешь библиотеку, ты не можешь всегда точно знать какие ещё библиотеки используются
источник

AP

Anton Petrusevich in Modern::Perl
то есть библиотеки в проекте, соотно, ты не всегда знаешь источники данных.
источник

OP

Oleg Pronin in Modern::Perl
Да но ты должен знать формат отдачи из стека либ байты или нет. Это всегда обычно выглядит как если там протокол с парсингом то символы а если поток то байты
источник

AP

Anton Petrusevich in Modern::Perl
когда ты пишешь приложение, то там, как правило, всё боле-мене понятно. если, конечно, какой нить DI не используется, но вот приходящие данные в библиотеку —- тут часто надо проверить есть там уже ютф8 или нет
источник

OP

Oleg Pronin in Modern::Perl
Ни разу за жизнь не юзал эту функцию
источник

OP

Oleg Pronin in Modern::Perl
Библиотеки которые плюются то так то так это чтото странное
источник

OP

Oleg Pronin in Modern::Perl
Позволяя принимать в либу и так и так ты только поощряешь неразбериху
источник

OP

Oleg Pronin in Modern::Perl
Должны быть четко отпределено или стрим или строки
источник

AP

Anton Petrusevich in Modern::Perl
ну да, ну да
источник

OP

Oleg Pronin in Modern::Perl
В других языках например это вообще разные классы! Во флеше например это были string и ByteArray
источник

OP

Oleg Pronin in Modern::Perl
И ты не примешь и то и то
источник

OP

Oleg Pronin in Modern::Perl
Да там и нет таких проблем. Проблема от сведения 2 в 1 все
источник

OP

Oleg Pronin in Modern::Perl
Oleg Pronin
Должны быть четко отпределено или стрим или строки
Исходя из смысла, логики. Если мы принимаем поток данных то строго бинарный, если поля структуры для энкода - строго строки
источник

OP

Oleg Pronin in Modern::Perl
И да еще забыл
7) use utf8;
Не имеет ничего общего с рантайм перекодировками данных, это просто хелпер который автомат делает decode_utf8 на все литералы написанные в этом файле / области видимости. Таким образом все литералы становятся строками. Но вычитанные в рантайме нет!
Обычно мало захардкоженных не инглиш строк в программе, поэтому он не особо полезен.
источник