Как найти длину строки Unicode в Perl?
Страница perldoc
для length() говорит мне, что я должен использовать bytes::length(EXPR)
для поиска строки Unicode в байтах или страница bytes повторяет это.
use bytes;
$ascii = 'Lorem ipsum dolor sit amet';
$unicode = 'Lørëm ípsüm dölör sît åmét';
print "ASCII: " . length($ascii) . "\n";
print "ASCII bytes: " . bytes::length($ascii) . "\n";
print "Unicode: " . length($unicode) . "\n";
print "Unicode bytes: " . bytes::length($unicode) . "\n";
Выход этого script, однако, не согласуется с man-страницей:
ASCII: 26
ASCII bytes: 26
Unicode: 35
Unicode bytes: 35
Мне кажется, length() и bytes:: length() возвращают то же самое для строк ASCII и Unicode. У меня есть мой редактор для записи файлов как UTF-8 по умолчанию, поэтому я считаю, что Perl интерпретирует весь script как Unicode - означает ли это, что length() автоматически обрабатывает строки Unicode правильно?
Изменить: См. мой комментарий; мой вопрос не имеет большого смысла, потому что length() не работает "правильно" в приведенном выше примере - он показывает длину строки Unicode в байтах, а не в символах. Резонанс, который я первоначально наткнулся на это, - это программа, в которой мне нужно установить заголовок Content-Lenth (в байтах) в сообщении HTTP. Я прочитал в Unicode в Perl и ожидал, что вам нужно будет сделать какое-то причудливое отношение, чтобы заставить все работать, но когда length() вернул именно то, что мне нужно было прямо с места в карьер, я был в замешательстве! См. Принятый ответ для обзора use utf8
, use bytes
и no bytes
в Perl.
Ответы
Ответ 1
Если ваши сценарии закодированы в UTF-8, используйте, пожалуйста, utf8 pragma. С другой стороны, bytes pragma будет принудительно использовать семантику байтов по длине, даже если строка UTF-8. Оба работают в текущей лексической области.
$ascii = 'Lorem ipsum dolor sit amet';
{
use utf8;
$unicode = 'Lørëm ípsüm dölör sît åmét';
}
$not_unicode = 'Lørëm ípsüm dölör sît åmét';
no bytes; # default, can be omitted
print "Character semantics:\n";
print "ASCII: ", length($ascii), "\n";
print "Unicode: ", length($unicode), "\n";
print "Not-Unicode: ", length($not_unicode), "\n";
print "----\n";
use bytes;
print "Byte semantics:\n";
print "ASCII: ", length($ascii), "\n";
print "Unicode: ", length($unicode), "\n";
print "Not-Unicode: ", length($not_unicode), "\n";
Выводится:
Character semantics:
ASCII: 26
Unicode: 26
Not-Unicode: 35
----
Byte semantics:
ASCII: 26
Unicode: 35
Not-Unicode: 35
Ответ 2
Цель bytes
pragma - заменить функцию length
(и несколько других связанных с строкой функций) в текущем объем. Поэтому каждый вызов length
в вашей программе - это вызов length
, который предоставляет bytes
. Это больше соответствует тому, что вы пытались сделать:
#!/usr/bin/perl
use strict;
use warnings;
sub bytes($) {
use bytes;
return length shift;
}
my $ascii = "foo"; #really UTF-8, but everything is in the ASCII range
my $utf8 = "\x{24d5}\x{24de}\x{24de}";
print "[$ascii] characters: ", length $ascii, "\n",
"[$ascii] bytes : ", bytes $ascii, "\n",
"[$utf8] characters: ", length $utf8, "\n",
"[$utf8] bytes : ", bytes $utf8, "\n";
Еще один тонкий изъян в ваших рассуждениях заключается в том, что существует такая вещь, как байты Unicode. Unicode - это перечисление символов. В нем, например, говорится, что U + 24d5 является & # x24d5 (CIRCLED LATIN SMALL LETTER F); Что Unicode не определяет, сколько байтов занимает символ. Это остается в кодировках. UTF-8 говорит, что он занимает 3 байта, UTF-16 говорит, что он занимает 2 байта, UTF-32 говорит, что он занимает 4 байта и т.д. Вот сравнение кодировок Unicode. По умолчанию Perl использует UTF-8 для своих строк. UTF-8 имеет преимущество во всех отношениях быть идентичным ASCII для первых 127 символов.
Ответ 3
Я обнаружил, что можно использовать модуль Encode, чтобы влиять на работу длины.
если $string - строка, закодированная в utf8.
Encode:: _ utf8_on ($ строка); # функция длины покажет количество кодовых точек после этого.
Encode:: _ utf8_off ($ строка); # функция длины покажет количество байтов в строке после этого.