Юникод жонглирование с Perl - PullRequest
2 голосов
/ 23 ноября 2011

У меня есть проблема, которую я считаю тривиальной.Мне приходится иметь дело с умлаутами из немецкого алфавита (äöü).В Unicode, кажется, есть несколько способов их отображения, один из которых - объединение символов.Мне нужно нормализовать эти разные способы, заменить их все односимвольным кодом.

Такой девиантный умлаут легко найти: это буква aou, за которой следует UTF-8 char \uCC88,Поэтому я подумал, что регулярного выражения будет достаточно.

Это моя функция преобразования, использующая пакет Encoding.

# This sub can be extended to include more conversions
sub convert {
    local $_;
    $_ = shift;

    $_ = encode( "utf-8", $_ );

    s/u\xcc\x88/ü/g;
    s/a\xcc\x88/ä/g;
    s/o\xcc\x88/ö/g;
    s/U\xcc\x88/Ü/g;
    s/A\xcc\x88/Ä/g;
    s/O\xcc\x88/Ö/g;

    return $_;
}

Но полученное в результате печатное умлауте - это дажеболее коварный символ (теперь занимает 4 байта) вместо того, что в этом списке .

Я думаю, проблема в том, что это жонглирование внутренним форматом Perl, фактическим UTF-8 и этим форматом кодирования.

Даже изменение строк замещения на

s/u\xcc\x88/\xc3\xbc/g;
s/a\xcc\x88/\xc3\xa4/g;
s/o\xcc\x88/\xc3\xb6/g;
s/U\xcc\x88/\xc3\x9c/g;
s/A\xcc\x88/\xc3\x84/g;
s/O\xcc\x88/\xc3\x96/g;

не помогло, они были преобразованы правильно, но затем в байтах следует "\ xC2 \ xA4".

Любая помощь?

1 Ответ

10 голосов
/ 23 ноября 2011

Вы делаете это неправильно: вы должны отказаться от привычки возиться с символами на уровне представления, то есть не возиться с байтами в регулярном выражении при работе с текстом, а не с двоичными данными.

Первыйшаг должен изучить тему кодирования в Perl .Это необходимо для понимания термина «строки символов», который я собираюсь использовать в следующем абзаце.

Если у вас есть строка символов, она может находиться в любом из различных состояний (де) композиции.Используйте модуль Unicode :: Normalize , чтобы изменить строку символов, и прочитайте соответствующие главы об эквивалентности и нормализации в спецификации Unicode для подробностей, они связаны в нижней части документации этого модуля.

Полагаю, вы хотите NFC, но вам нужно проверить правильность данных, чтобы увидеть, действительно ли это ожидаемый результат.

use charnames qw(:full);
use Unicode::Normalize qw(NFC);
my $original_character_string = "In des Waldes tiefsten Gr\N{LATIN SMALL LETTER U WITH DIAERESIS}nden ist kein R\N{LATIN SMALL LETTER A}\N{COMBINING DIAERESIS}uber mehr zu finden.";
my $modified_character_string = NFC($original_character_string);
# "In des Waldes tiefsten Gr\x{fc}nden ist kein R\x{e4}uber mehr zu finden."
...