Comments 73
Жгут =)
Такое лаконичное решение.
Долго думал. :)
Долго думал. :)
Кстати, а для чего вообще нужно такое решение?
Ведь если я отдаю страницу в UTF-8,
то зачем мне предполагать, что форма придет в WIN1251?
То же самое, если наоборот.
Ведь если я отдаю страницу в UTF-8,
то зачем мне предполагать, что форма придет в WIN1251?
То же самое, если наоборот.
Потому что кулхацкеры не дремлют.
Прежде всего потому что работать с UTF-8 не убедившись в том, что это UTF-8 нельзя. Можно много разных дров наломать.
Определить, что строка — однозначно UTF-8, а никакая другая, тоже нельзя.
Все эти проверки проверяют лишь может ли строка быть в UTF-8 или нет.
PS: прошу пример поломаных дров
Все эти проверки проверяют лишь может ли строка быть в UTF-8 или нет.
PS: прошу пример поломаных дров
Все эти проверки проверяют лишь может ли строка быть в UTF-8 или нет.А большего и не надо. Если клиент сказал что текст будет в UTF-8, а прислал нечто в windows-1251, которое выглядит как UTF-8 — то он ССЗБ (сам себе злобный Буратина).
PS: прошу пример поломаных дровВнизу — пример очевидный и довольно серъёзный, но уже не очень актуальный. Другой пример — спамфильтры. Вы можете использовать хитрые символы в URL, а невалидный UTF-8 обломает вам всю нормализацию. При этом вырезание лишнего (скажем тега <script>) склеит вам пресловутую точку (она из нескольких байт в UTF-8 состоит) и она «возродится из пепла». Да, можно на каждом шаге при обработке текста думать «а не создались ли у нас тут новые хитрые юникодные симвлы после того, как мы что вырезали/заменили/etc), а можно — убедиться что у нас на входе UTF-8 и больше уже об этом не задумываться. Кроме проверки UTF-8 на валидность хорошо бы ещё нормализацию провести — но это уже от конкретных алгоритмов зависит. Нормализация — штука медленная, сложная и неоднозначная, проверка UTF-8 на валидность — вещь быстрая и простая (особенно если через PCRE делать).
Эта проблема применима и к другим кодировкам, например: <<script>iframe… >
и решается только итерационным методом.
Если я предполагаю, что строка — UTF-8 то возродившиеся символы — будут рассмотрены в новой итерации вполне корректно.
и решается только итерационным методом.
Если я предполагаю, что строка — UTF-8 то возродившиеся символы — будут рассмотрены в новой итерации вполне корректно.
Эта проблема применима и к другим кодировкам, например: <<script>iframe… >Только к мультибайтовым. Когда вы удаляете из <<script>iframe… > <script> там не появляется новых символов (code points). Новые подстроки — да, появляются и за этим нужно сделать. Но новые символы — нет. В испорченной многобайтовой кодировке могут появляться новые символы — и это совсем другая проблема. Собственно корейцы там не только UTF-8 на валидность проверяют.
Если я предполагаю, что строка — UTF-8 то возродившиеся символы — будут рассмотрены в новой итерации вполне корректно.У вас программа интерактивно по очереди вырезает сначала лишние теги, потом spam, потом снова теги, потом снова spam и так — пока процесс не сойдётся к чему-нибудь? Тоже вариант, конечно. Но доказать корректность этой деятельности куда сложнее, чем просто предварительно убедиться что у вас данные — не испорчены.
Ах да — после каждого вырезания тегов и обработки на spam нужно ещё раз нормализацию проводить! Тоже затраты…
пока процесс не сойдётся к чему-нибудь?
нет, только до тех пор, пока строка не изменится.
А расскажите в двух словах, как вы боретесь с вышеуказанной проблемой, пусть даже не мультибайтовой. Разве не итерационно?
> то ли китайцы, то ли индусы.
Я бы сказал, корейцы.
Я бы сказал, корейцы.
Корейцы. =)
есть же велосипедисты, в манах по пхп и то есть ))
// Returns true if $string is valid UTF-8 and false otherwise.
function is_utf8($string) {
// From w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
} // function is_utf8
// Returns true if $string is valid UTF-8 and false otherwise.
function is_utf8($string) {
// From w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
} // function is_utf8
Есть вариант без регекспов:
function is_utf8($string) { for ($i=0; $i<strlen($string); $i++) { if (ord($string[$i]) < 0x80) continue; elseif ((ord($string[$i]) & 0xE0) == 0xC0) $n=1; elseif ((ord($string[$i]) & 0xF0) == 0xE0) $n=2; elseif ((ord($string[$i]) & 0xF8) == 0xF0) $n=3; elseif ((ord($string[$i]) & 0xFC) == 0xF8) $n=4; elseif ((ord($string[$i]) & 0xFE) == 0xFC) $n=5; else return false; for ($j=0; $j<$n; $j++) { if ((++$i == strlen($string)) || ((ord($string[$i]) & 0xC0) != 0x80)) return false; } } return true; }
может вопрос конечно глупый но все же… а как узнать наверняка это UTF8 или нет?
Сильно-сильно в это верить
Ну либо вызовом iconv'а, либо вышеприведённым regexp'ом. С учётом того, что iconv работает быстрее в нормальном случае и в случае строк длиной в сотню байт и больше — я бы выбрал решение из топика.
Есть регулярка, описанная выше. Кроме того в движке википедии используется её упрощённый вариант, могу показать.
Вот так: bolknote.ru/2008/03/20/~1632/
С большой вероятностью можно так проверить: mb_check_encoding($str, 'UTF-8')
Для этого нужен модуль multibyte
Ну да, нужен. На сколько мне известно, на большинстве хостингов он включен. Хотя могу ошибаться.
Большинство — не все. Можно определять и без него, способ я указал выше.
Не стоит прогибаться под изменчивый мир ©
Говорю же — есть способ лучше. Кстати, песня та очень безрадостно кончается.
UFO just landed and posted this here
на C есть замечательная библиотека libenca, а так старый и добрый метод явное указание кодировки ;)
Причём тут указание кодировки? Если вам на вход подадут испорченный файл в котором между байтами 0xC0 и 0xBC будет написано слово "<script>" — то вы можете это слово вырезать, байты 0xC0 и 0xBC сольются и образуют символ "<" — а уже слово script после него может остаться. С валидной UTF-8 строкой такого случиться не может. Потому даже если вы точно знаете что у вас UTF-8 на входе, а не какая-либо другая кодировка — проверка лишней не будет.
(заинтересованно) А как это они так сольются, чтобы образовать символ "<"?
Очень просто. Посмотрите как получаются из UTF-8 символы в UTF-16 или UTF-32. И подумайте во что превратятся два байта 0xC0 и 0xBC :-) Конечно это случится только в том случае когда проверки не будет в Web-браузере — но лучше перебдеть, чем недобдеть и проверить строку дважды (на сервере и в браузере), чем ни разу (браузер понадеется на веб-сайт, веб-сайт — на браузер, в результате у посетителя вашего сайта деньги уведут — кому от этого хорошо будет?).
Ага, понятно. Правда, в спецификации:
An important note for developers of UTF-8 decoding routines: For security reasons, a UTF-8 decoder must not accept UTF-8 sequences that are longer than necessary to encode a character.
Собственно, ни один из подручных utf-8 агентов и не воспринял последовательность как <.
An important note for developers of UTF-8 decoding routines: For security reasons, a UTF-8 decoder must not accept UTF-8 sequences that are longer than necessary to encode a character.
Собственно, ни один из подручных utf-8 агентов и не воспринял последовательность как <.
Пардон, зачем писать
return true;
else
return false;
если будет ретурн первый, то уже совсем не важно что будет в else, а это как никак целая строчка лишнего кода.
return true;
else
return false;
если будет ретурн первый, то уже совсем не важно что будет в else, а это как никак целая строчка лишнего кода.
Спасибо! В избранное
Нууууу, ведь суть в том, что это работает? Да и код не особо не бредовый, бывает хуже :)
А что вам не нравится? Работает ведь. Скорость проверки сильно ниже регэкспа?
на govnokod.ru/!
он просто был создан пхпшникам руснета :)
Я выборочно потыкал в Cи, Си++, Perl, там пусто. Так что не показательно.
govnokod.ru/best/asm?time=ever
Вот это точно показательно. У питона не было говнокода один день, у асма — никогда.
Вот это точно показательно. У питона не было говнокода один день, у асма — никогда.
Ошибка: «корейцы» нужно написать с маленькой буквы.
Скажите пожалуйста как это работает?
my $cv = Text::Iconv->new('utf-8','windows-1251');
$File_path = $cv->convert($File_path);
my $cW = Text::Iconv->new('windows-1251','windows-1251');
$File_path = $cW->convert($File_path);
$File_path = $cv->convert($File_path);
my $cW = Text::Iconv->new('windows-1251','windows-1251');
$File_path = $cW->convert($File_path);
интересует переменная $cW конечно же.
# locale
LANG=ru_RU.CP1251
LC_CTYPE=«ru_RU.CP1251»
LC_NUMERIC=«ru_RU.CP1251»
LC_TIME=«ru_RU.CP1251»
LC_COLLATE=«ru_RU.CP1251»
LC_MONETARY=«ru_RU.CP1251»
LC_MESSAGES=«ru_RU.CP1251»
LC_PAPER=«ru_RU.CP1251»
LC_NAME=«ru_RU.CP1251»
LC_ADDRESS=«ru_RU.CP1251»
LC_TELEPHONE=«ru_RU.CP1251»
LC_MEASUREMENT=«ru_RU.CP1251»
LC_IDENTIFICATION=«ru_RU.CP1251»
LC_ALL=
Имена файлов в cp1251… все должно работать без этого велосипеда, но не работает!
Результат записывается в мускул, там тоже по дефолту 1251.
# locale
LANG=ru_RU.CP1251
LC_CTYPE=«ru_RU.CP1251»
LC_NUMERIC=«ru_RU.CP1251»
LC_TIME=«ru_RU.CP1251»
LC_COLLATE=«ru_RU.CP1251»
LC_MONETARY=«ru_RU.CP1251»
LC_MESSAGES=«ru_RU.CP1251»
LC_PAPER=«ru_RU.CP1251»
LC_NAME=«ru_RU.CP1251»
LC_ADDRESS=«ru_RU.CP1251»
LC_TELEPHONE=«ru_RU.CP1251»
LC_MEASUREMENT=«ru_RU.CP1251»
LC_IDENTIFICATION=«ru_RU.CP1251»
LC_ALL=
Имена файлов в cp1251… все должно работать без этого велосипеда, но не работает!
Результат записывается в мускул, там тоже по дефолту 1251.
А кто такой cp1251?
;)
знаю только utf-8
;)
знаю только utf-8
Это конечно да, вы правы =)
Но речь идет о базе данных, файлы создаются через самбу виндовыми пользователями(т.е. имена в cp1251). Вложенность каталогов большая, размер 31 гигабайт, огроменное количество мелких файлов, все настолько ужасно что бекап занимает около 8 часов.
Если я буду использовать utf — перед архивацией потребуется копировать всю БД + рекурсивно пробегаться утилитой convmv… и обратные действия после восстановления бекапа, т.е. это дополнительное время и такой вариант, к сожалению не пойдет
(сейчас просто делаю tar -cvvf и все ок)
Собственно, вопрос стоял иначе — почему без строки
my $cW = Text::Iconv->new('windows-1251','windows-1251');
скрипт работает неправильно? Ведь локаль указана верно.
Но речь идет о базе данных, файлы создаются через самбу виндовыми пользователями(т.е. имена в cp1251). Вложенность каталогов большая, размер 31 гигабайт, огроменное количество мелких файлов, все настолько ужасно что бекап занимает около 8 часов.
Если я буду использовать utf — перед архивацией потребуется копировать всю БД + рекурсивно пробегаться утилитой convmv… и обратные действия после восстановления бекапа, т.е. это дополнительное время и такой вариант, к сожалению не пойдет
(сейчас просто делаю tar -cvvf и все ок)
Собственно, вопрос стоял иначе — почему без строки
my $cW = Text::Iconv->new('windows-1251','windows-1251');
скрипт работает неправильно? Ведь локаль указана верно.
Капча текстом на том сайте это сильно :))
самое интересное что на мой вопрос про определение кодировки «нормальным» способом народ выдал либо еще бредовей идею либо ссылался на эту же… в чем тогда прикол «кодобреда»? или я что-то не понимаю?
Это бред, но идейно гениальный, т.к. другие решения не лучше.
Улучшение habrahabr.ru/blogs/code_wtf/48661/#comment_1262856
К стати в перле работа с utf — это вообще убийство…
Улучшение habrahabr.ru/blogs/code_wtf/48661/#comment_1262856
К стати в перле работа с utf — это вообще убийство…
Простите, но вы не уточняли где нужно определить кодировку? Windows, Linux, язык програмирования или БД… с чем вы работаете? =)
Конкретно в линукс есть утилита enca. Я с ней сталкивался при написании скриптов на языке perl.
Конкретно в линукс есть утилита enca. Я с ней сталкивался при написании скриптов на языке perl.
Мне интересно следить за темой «Кодобреда», но, как говорится, чужое заметить легко. Очень бы хотелось наряду с кодобредом видеть Ваше красивое решение того, что Вы высмеиваете :)
Sign up to leave a comment.
Строка в UTF-8?