Perl и utf-8

June 11, 2017 PERL UTF UTF-8 JSON

По заявлениям товарищей разработчиков дистрибутива Perl5, он уже давно поддерживает utf-8 из коробки. На практике по-умолчанию оно конечно кое-как поддерживается, но если попросить вывести, например, на экран или в файл utf-8 последовательность символов, среди которых есть много байтные мы словим ворнинг на тему wide characters. Кроме того в некоторых ситуация такая строка может побиться при таком вводе-выводе.
Оказывается, для совместимости со старыми скриптами, режим работы с utf-8 для файловых дескрипторов выключен, а для переменных (которые по-умолчанию - это строки во внутреннем представлении либо последовательности байтов) добавлен флажок, который индицирует является ли по мнению интерпретатора переменная строкой utf-8 или нет. При этом даже если флажок взведён переменная может и не быть валидной utf-8 строкой. Да и сам по себе флажок расставляется довольно странным образом... Зато есть возможность проверить его состояние.

Формально, при использовании use utf-8 мы вроде сообщаем интерпритатору, что по-умолчанию у переменных этот флажок должен быть взведён. Кроме того если таким образом задействовать utf-8, то меняется поведение некоторых функций, например length() начинает мерять длину переменных исходя из того, что в них utf-8 последовательность символов, а не байты, даже если там байты. Однако конструкция my $var = substr($string, $offset) частенько для $var не выставлет флажок utf-8, соответственно, чтобы оно сработало, нужно схитрить:

my $var;
$var = substr($string, $offset);

Есть сильно неприятное явление в такой "нативной" поддержке utf-8 - невозможно определить является ли содержимое переменной валидной последовательность utf-8 символов, функции, которая точно нам это скажет, просто нет в арсенале Perl-а. Приходится идти на некоторые ухищрения, например, такие:

$str = eval { decode('UTF-8', $str, Encode::FB_CROAK) } // ' ';

Конкретно в этом случае переменная $str либо останется неизменной (и у неё будет выставлен флажок utf-8, если он не был выставлен), либо будет заполнена пробелом.

Почему вообще возник такой вопрос - нужно было сформировать strict json строку, а в определении формата написано, что либо latin-1, либо utf-8, который должен быть strict utf-8, ибо на другой стороне парсер благополучно валился с ошибкой, чуть что не так.

Next Post