25 November 2008

Нормализация Unicode

Website development
Однажды мне пришлось наблюдать, как спамеры очень интересным образом обходят спам-фильтр. Вместо традиционного URL типа «example.com», ссылка выглядела так:
http://example.com
Ссылка с подобной изощрённой точкой работает в IE7, FF3, Opera 9.5, Safari 3, Google Chrome и не работает в IE6.

UAX #15: Unicode Normalization Forms


Немного подумав, я стал искать решение проблемы. Поскольку точка явно относилась к классу эзотерических Unicode-символов (как я узнал впоследствии, это — японская полноширинная точка), я решил заглянуть в соотвествующий стандарт, и там нашёл ответ на волнующий меня вопрос. Оказывается, существуют процедуры нормализации текста, после которого он пригоден для сравнения.

Композиция, декомпозиция, и преобразование экзотических символов


В Unicode есть 4 вида нормализации. Первые два из них — композиция и декомпозиция — позволяют справиться со следующими проблемами:
  • В Unicode одна и таже сложная буква типа «Ç» может быть представлена в двух формах: в виде единой буквы и в виде базовой буквы («C») и модификаторов. Процесс, при котором все буквы по возможности объединяются в одну, называется композицией (Normalization Form C, далее — NFC), а процесс, при котором все буквы по возможности разбиваются на модификаторы — декомпозицией (Normalization Form D, далее — NFD).
  • Если модификаторов несколько, то они могут быть разрбросаны в разном порядке.
  • Одна и та же буква может иметь несколько вариантов (например, «Ω» и «Ω»)

Чтобы пояснить всё вышесказанное, приведу несколько иллюстраций из стандарта:
NFC и NFD
NFC и NFD
Далее. Существует множество символов, типа вышепреведенной точки «.», которые выглядят очень похожими на другие и могут быть подло использованы спамерами. Специально для таких случаев существует Normalization Form KC (NFKC) и Normalization Form KD (NFKD), которые, помимо (де)композиции, нормализуют следующие символы:
  • Изощрённые шрифты (ℍ и ℌ)
  • Кружки (①)
  • Изменённый размер и угол поворота (カ и カ, ︷ и {)
  • Степени (⁹ и ₉)
  • Дроби (¼)
  • Другие (™)

Посмотрим в действии:
NFKC и NFKD
Таким образом, NFKC/NFKD — это именно то, что нам надо для защиты от спамеров и прочей нечисти. Осталось только прикрутить это к программе.

Реализация

  1. Для C/C++ есть библиотека ICU — я думаю, что большинство, кому приходилось работать с Unicode под C/C++, знают о ней. Для тех, кто не знает: вот официальный сайт. В ICU вся нормализация выполняется через класс Normalizer.
  2. Для Java есть та же ICU и тот же класс Normalizer
  3. Для PHP всё сложнее. Я знаю как минимум два способа:
    • Использовать класс Normalizer из библиотеки intl.
    • Если по каким-то причинам невозможно использовать библиотеку intl, можно взять готовую реализацию из MediaWiki (через SVN), которая реализована там в виде независимой подсистемы.

Приведу банальный пример (в связи с основным языком и основным проектом буду использовать последнюю указанную мной библиотеку):
<?php
require_once( 'normal/UtfNormal.php' );
$input = "http://example.com";
echo
"{$input}\n";
echo
UtfNormal::toNFKC( $input ) . "\n";


Выводит эта программа следующее:
http://example.com
http://example.com

Итог


Как мы видим, NFKC/NFKD позволяет нам урезать возможности для «игры с буквами», и незаменим в спам-фильтрах и матоблокировщиках. NFC вдобавок позволяет нам сжать текст.
Tags:unicodeантиспам
Hubs: Website development
+124
13.7k 117
Comments 27
Top of the last 24 hours