Веб-разработка

индекс
237,17

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

Однажды мне пришлось наблюдать, как спамеры очень интересным образом обходят спам-фильтр. Вместо традиционного 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 вдобавок позволяет нам сжать текст.
_________
Текст подготовлен в ХабраРедакторе
+124
25 ноября 2008, 20:02
107

комментарии (26)

+7
kurokikaze #
Очень интересно, спасибо :)
+5
zloe_zlo #
Не знал. Спасибо за статью.
0
Onoto1ey #
почитал, почерпнул много нового, говорю спасибо ^_^
0
321 #
Спасибо за статью, интерсно. =)
+2
khim #
Одно но: NFKx могут вам текст изуродовать до полной неузнаваемости, так как прератят X² в X2. Но для спама это, конечно, вариант.
0
flaresun #
Но ведь можно текст «изуродовать», проверить на спам и, если всё ок, то записать его в базе/файл в изначальном виде…
+4
khim #
Я собственно о том, что именно так и надо делать. Записывать в базу NFC можно, NFKC — ни в коем случае.
0
p4s8x #
Насамом деле очень и очень познавательно!
0
Nuty #
В дополнение статья на вики ru.wikipedia.org/wiki/Unicode
+1
khim #
Ага. И ещё туточки много чего написано. Гулять, так гулять, да?
0
Nuty #
Погуглить никогда не вредно)
0
archimonde #
Спасибо, очень познавательно и интересно
+3
aulismedia #
Спасибо за статью. Примечательная особенность Хабра в отличие от тех же обучающих и советующих сайтов на английском — люди в ASCII-мире не задумываются о проблемах национальных кодировок и толковой помощи от них не жди.
+4
zw0rk #
И именно поэтому весь мир переходит на УТФ8 в основном стараниями тех самых ASCII-жителей :)
+4
zencd #
Novikov знает? :-)
+2
anight #
А еще decomposed unicode используется по-умолчанию в MacOSX.
Я написал модуль для прозрачного перекодирования NFD -> NFC для macosx, если кому будет полезно.

code.google.com/p/nfd2nfc/
+7
tty01 #
Однажды я прогуливался по мосту и увидел человека, стоящего на краю, который собирался прыгнуть. Я быстро подбежал к нему и сказал «Стой! Не делай этого!»
«Я ничего не могу поделать» — плакал он, «я потерял интерес к жизни».
«Чем ты зарабатываешь на жизнь?» — спросил я.
Он сказал: «Я разрабатываю технические требования для веб-сервисов»
«Я тоже!» — сказал я. «Ты используешь REST-сервисы или SOAP-сервисы?»
Он сказал: «REST-сервисы»
«Я тоже!» — сказал я. «Ты используешь текстовой формат XML или бинарный формат XML?»
Он сказал: «текстовой формат XML»
«Я тоже!» — сказал я. «Ты используешь XML 1.0 или XML 1.1?»
Он сказал: «XML 1.0»
«Я тоже!» — сказал я. «Ты используешь UTF-8 или UTF-16?»
Он сказал: «UTF-8»
«Я тоже!» — сказал я. «Ты используешь нормализацию юникода формы C или нормализацию юникода формы KC?»
Он сказал: «нормализацию юникода формы KC»
«Умри, иноверная мразь!» — прокричал я, и столкнул его с моста.

tty01.blogspot.com/2004/07/unicode-normalization-form-c.html
0
7vies #
У меня вот так вот выглядит:



Не подскажете, что нужно сделать, чтобы в фф были нормальные буквы вместо квадратиков? А то надоело уже :( Кстати, это не только в браузере, не нашёл пока ни одного приложения у себя которое бы нормально отображало этот символ, в винде (XP SP2) что-то не так настроено?
–1
vasilievvv #
Точка японская
0
khim #
У вас поддержка азиатских языков установлена? MS IE до сих пор с Unicode не дружит (интерсно, кстати, как с этим в 8й версии), но в Firefox всё должно быть нормально…
+1
khim #
Control Panel->Regional And Language Settings->Languages->Install files for complex scripts and right-to-left languages
Control Panel->Regional And Language Settings->Languages->Install fonts for East Asian languages

P.S. Я исхожу из того что у вас нормальная лицензионная винда: эти самые шрифты много весят, по умолчанию не ставятся и потому являются первым что пираты выбрасывают с CD чтобы сделать сборники типа «8 версий Windows в одном!»…
0
7vies #
Действительно, что-то я не подумал про поддержку азиатских языков. Может, из-за этого у меня периодически квадратики и возникают. CD нету… эхх, остаюсь я, похоже, без японских точек :)
0
imagick #
Было такое. Искал долго, в чем же дело. Оказалось — в файрволле. В Аутпосте. После его обновления больше не проявлялось.
0
allter #
Вроде, NFK* не приведут национальные символы, к латинице. Т.е. NFKD для русского «ё» = русское «е» + комбинирующий ":", а не латинское «e». Да и для того, что бы канонически разложить Ж, скажем, на >I< надо свою либу писать…
0
vasilievvv #
А я говорил, что NFKC приводит русскую «e» в английскую? Для полного визуального соответствия можно ещё добавить это, но вот еxample.com вам к example.com браузер не приравняет.
НЛО прилетело и опубликовало эту надпись здесь

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