Проблема в стемере для PHP
В модуле stem для ПХП обнаружилась неожиданная проблема. Этот модуль — стеммер, позволяющий обрезать окончания слов для того, чтобы искать потом по тексту без учёта падежей и склонений.
Для русского языка в нём целых две функции — для кодировки КОИ-8 и УТФ-8. Наш код работает в КС1251, потому для стеммера мы перегоняем текст в УТФ-8.
Я обратил внимание, что из командной строки код с этим модулем работает нормально, а в рабочем проекте кодировка портится — как будто стеммер где-то внутри себя рассматривает УТФ-8 как однобайтовую русскую кодировку и приводит её к нижнему регистру.
У меня возникла мысль, что дело в выставляемой локали, мы провели эксперимент — так и есть, дело в этом. Такой код работать правильно не будет:
setlocale(LC_TIME, 'ru_RU.cp1251');
echo stem_russian_unicode(iconv('windows-1251', 'utf-8', 'Приветы'));
Кодировка получится битой. Перед вызовом функций стеммера нужно переставлять кодировку (setlocale) в УТФ-8. Ошибочное место в модуле ищется элементарно:
// файл stem.c
php_strtolower(z->p, arglen); // ← вот искомый вызов
stem(z);
z->p[z->l]= '\0';
// … ищем эту функцию в исходниках PHP…
// string.c из PHP
PHPAPI char* php_strtolower(char * s, size_t len) {
unsigned char *c, *e;
c = (unsigned char *)s;
e = c+len;
while (c < e) {
*c = tolower(*c); // ← а это проблемное место
c++;
}
return s;
}
Согласно манам, функция tolower ориентируется в своей работе на локаль, в этом и проблема.
Наверное, КС1251, а не КД1251?
Комментарий для spiridonov@gmail.com:
Да, спасибо. Ума не приложу почему написал «КД» :)
Комментарий для Евгения Степанищева:
Ну КС1251 это вообще апогей зла. Это вы так мастерски набросили? %)
Комментарий для hshhhhh.name:
Почему это апогей зла, я что-то не понял. 1251 — это кодовая страница. Что не так-то?
Комментарий для hshhhhh.name:
http://www.google.com/search?q=%22%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2%D0%B0%D1%8F%20%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0%201251%22%26ie=utf-8%26oe=utf-8
ну , все привыкли «кодировка cp1251» , сразу всё понятно. А прочитав «КС1251» как-то не сразу понятно что имеется в виду.
Комментарий для dinoelq:
«Кодировка эсэр1251» :)
Люди вообще ко многому плохому привыкли. К «кавычкам» от печатающих машинок, отсутствию падежей у Домодедово, к написанию McDonald’s на российских забегаловках этой сети, к юзанью иностранных слов, там где есть свои и так далее :)
Когда я писал «КС1251» я не имел ввиду «кодировка с названием „CP1251“», я имел ввиду «кодовая страница 1251».