Perl 6 сразу и без обиняков считает исходный текст программы сохраненным в UTF-8. Да и вообще, поддержка юникода в Perl 6 очен радует. Сегодня посмотрим, как узнать длину строки.
Решение в лоб, знакомое по опыту Perl 5, не работает. На попытку вызвать функцию length компилятор выдает инструкцию воспользоваться новыми возможностями:
Undeclared routine: length used at line 1. Did you mean 'elems', 'chars', 'codes'?
elems, chars и codes
Метод elems относится скорее к массивам, чем к строкам. А вот с chars и codes давайте разберемся.
Метод символов в строке:
say 'hello'.chars; # 5 say 'café'.chars; # 4 say 'привет'.chars; # 6 say '嗨'.chars; # 1
Все отлично работает независимо от языка и наличия диакритических знаков.
Метод codes возвращает число кодовых позиций, необходимых для записи строки. Во многих случаях результат будет совпадать с тем, что возвращает chars. Если же юникодный символ собран из таких частей, которые невозможно воспроизвести в одиночном символе (например, буква плюс какой-то хитрый диакритический знак, который в известных языках не применяется с данной буквой), то Perl не сможет привести этот символ к каноническому виду и, соответственно, chars покажет 1, а codes — 2.
Длина в байтах
Если нужно определить длину строки в байтах, то просто вызвать метод, например, bytes, не получится. Хотя скорее всего вы имели в виду кодировку UTF-8, Perl 6 желает услышать это явно. Действительно, при разном кодировании одна и та же строка занимет разное число байтов. Вот как это делается:
say 'hello'.encode('UTF-8').bytes; # 5 say 'café'.encode('UTF-8').bytes; # 5 say 'привет'.encode('UTF-8').bytes; # 12 say '嗨'.encode('UTF-8').bytes; # 3
В UTF-16, например, число байт будет отличаться:
say 'hello'.encode('UTF-16').bytes; # 10 say 'café'.encode('UTF-16').bytes; # 8 say 'привет'.encode('UTF-16').bytes; # 12 say '嗨'.encode('UTF-16').bytes; # 2
Разумеется, при попытке посчитать байты в Latin-1, часть строк не сможет быть конвертирована:
$ perl6 -e'say "ю".encode("Latin-1")' Error encoding Latin-1 string: could not encode codepoint 1102 in block at -e line 1