Как использовать Unicode :: Normalize для создания наиболее совместимой строки в кодировке Windows-1252? - PullRequest
0 голосов
/ 18 января 2019

У меня есть устаревшее приложение в Perl, которое, скорее всего, обрабатывает XML, закодированный в UTF-8, и которому необходимо хранить некоторые данные этого XML в некоторой базе данных, которая использует windows-1252 по историческим причинам. Да, эта установка не может поддерживать все возможные символы стандарта Unicode, но на практике мне все равно это не нужно и я могу попытаться быть разумно совместимым.

Конкретной проблемой в настоящее время является файл, содержащий LATIN SMALL LETTER U, COMBINING DIAERESIS (U+0075 U+0308), что заставляет Perl разбить существующую кодировку строки Unicode на windows-1252 со следующим исключением:

"\ x {0308}" не отображается на cp1252

Мне удалось обойти эту проблему, используя Unicode :: Normalize :: NFKC , который создает символ U+00FC (ü), который прекрасно отображается на windows-1252. Это приводит к некоторой другой проблеме, например, например. в случае символа VULGAR FRACTION ONE HALF (½, U+00BD), потому что NFKC создает для этого DIGIT ONE, FRACTION SLASH, DIGIT TWO (1/2, U+0031 U+2044 U+0032) и Perl снова умирает:

"\ x {2044}" не сопоставляется с cp1252

Согласно правилам нормализации , это прекрасно для NFKC. Я использовал это, потому что я думал, что это даст мне наиболее совместимый результат, но это было неправильно. Использование NFC вместо этого решило обе проблемы, поскольку оба символа обеспечивают нормализацию , совместимую с windows-1252 в этом случае.

Этот подход становится еще более проблематичным для символов, для которых нормализация, совместимая с windows-1252, в целом доступна, отличается только от NFC. Одним из примеров является LATIN SMALL LIGATURE FI (, U+FB01). Согласно правилам нормализации , его представление после NFC несовместимо с windows-1252, а при использовании NFKC на этот раз два символа совместимы с windows-1252: fi (U+0066 U+0069) .

Мой нынешний подход заключается в том, чтобы просто попробовать кодировать как windows-1252 как есть, если это не удастся, я использую NFC и повторить попытку, если это не удастся, я использую NFKC и повторить попытку, и если это не удастся, я Я сдаюсь на данный момент. Это работает в тех случаях, с которыми я сейчас имею дело, но, очевидно, не работает, если все три символа из моих примеров выше присутствуют в строке одновременно. Тогда всегда есть один символ, что приводит к windows-1252 -совместимому выводу, независимо от порядка NFC и NFKC. Вопрос только в том, какой персонаж сломается, когда.

НО важным моментом является то, что каждый символ сам по себе может быть нормализован к чему-то, совместимому с windows-1252. Только кажется, что нет единого решения.

Итак, есть ли какой-то API, который мне не хватает, который уже конвертируется наиболее обратно совместимым способом?

Если нет, то какой подход мне нужно реализовать самому, чтобы поддерживать все вышеперечисленные символы в одной строке?

Звучит так, будто мне нужно обработать каждую строку Unicode-символа Unicode-символом, индивидуально нормализовать с тем, что наиболее совместимо с windows-1252, и затем снова объединить результаты. Есть ли какой-нибудь инкрементный синтаксический анализатор Unicode-символов, который уже занимается комбинированием символов и прочего? Обрабатывает ли это уже простое регулярное выражение на основе Unicode?

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

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Так как кажется, что вы можете конвертировать отдельные символы по мере необходимости (в кодировку cp-1252), один из способов заключается в том, чтобы обрабатывать символ за символом, как это предлагается, когда слово не проходит процедуру.

\X в регулярном выражении Perl соответствует логическому символу Unicode, кластеру расширенной графемы , либо в виде единой кодовой точки, либо в виде последовательности.Поэтому, если вы действительно можете преобразовать все отдельные (логические) символы в нужную кодировку, то с помощью

while ($word =~ /(\X)/g) { ... }

вы можете получить доступ к логическим символам и применить свою рабочую процедуру к каждому.

В случае, еслиВы не можете обработать все логические символы, которые могут появиться, собрать воедино эквивалент \X, используя конкретные свойства символов , для более тонкой детализации с комбинированием меток или тому подобного (например, /((.)\p{Mn}?)/ или \p{Nonspacing_Mark}).Полный, грандиозный, список находится в perluniprops .

0 голосов
/ 18 января 2019

Я не думаю, что вам не хватает API, потому что достаточно сложный подход.Я бы попробовал что-то вроде следующего:

  • Нормализация с использованием NFC.Это объединяет разложенные последовательности, такие как LATIN SMALL LETTER U, DIAERESIS КОМБИНИРОВАНИЯ.
  • Извлечение всех кодовых точек, которые не объединяют метки, используя регулярное выражение /\PM/g.Это отбрасывает все метки объединения, оставшиеся после преобразования NFC, которые не могут быть преобразованы в Windows-1252 в любом случае.Затем для каждой кодовой точки:
    • Если кодовая точка может быть преобразована в Windows-1252, сделайте это.
    • В противном случае попробуйте нормализовать кодовую точку с помощью NFKC.Если отображение NFKC отличается от входного, примените все шаги рекурсивно к результирующей строке.Это обрабатывает такие вещи, как лигатуры.
    • В качестве бонуса: если кодовая точка инвариантна относительно NFKC, преобразуйте ее в NFD и попытайтесь преобразовать первую кодовую точку результата в Windows-1252.Это преобразует символы, такие как Ĝ, в G.
    • В противном случае игнорируйте символ.

Конечно, существуют другие подходы, которые преобразуют неподдерживаемые символы в символы, похожие на похожие, ноони требуют создания отображений вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...