Как найти длину строки 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 ($ строка); # функция длины покажет количество байтов в строке после этого.