set_locale str_word_count и чёртова буква я

GrayHound

Новичок
set_locale str_word_count и чёртова буква я

Ткните носом чтоли.
Поставил setlocale(LC_ALL, 'ru_RU.cp1251');
str_word_count слова находит отлично, но почти... буква "я" у него почему в наш алфавит похоже не входит, и работает как разделитель по сути... что делать?
 

phprus

Moderator
Команда форума
kruglov
Если мне не изменяет память, то функция isalpha стандартной библиотеки языка С нормально обработает букву с кодом 255, так как она принимает параметр типа int

Потому что у нее код 255 = EOF
255 != EOF
EOF в С определен как
#define EOF (-1)
тоесть по умолчанию он имеет тип int.

Дальнейшие мои рассуждения основаны на версии php 5.2.3, так как исходников других версий у меня нет.
В коде файла ext/standard/string.c есть такая строчка:
Код:
while (p < e && (isalpha(*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) {
Как мы видим в ней функции isalpha передается разыменованый указатель p, который имеет тип char*. Вот тут то и начинаются преобразования. 255 - это 8 единиц в битовом представлении. Для типа char это равносильно числу -1 Вот тут происходит преобразование типа с char в int и в функцию isalpha передается -1, а не 255(как мы ждали).

Для исправления этой ситуации достаточно принудительно преобразовать *p к типу unsigned char, тоесть если написать вызов isalpha таким образом:
Код:
isalpha([b](unsigned char)[/b]*p)
То буква "я" должна будет обрабатываться нормально.

P.S. Все вышесказанное писал по памяти, так как скомпилировать и проверить у меня сейчас возможности нет.
 

GrayHound

Новичок
phprus
инфо весьма полезное... но когда сайт лежит у хостера - я думаю он перекомпилировать не будет
 

Андрейка

Senior pomidor developer
мы конечно сипласпласов не изучали, но у нас есть некоторые сомнения, что интерпритация 8 единичек зависит от того signed или unsigned char передают в одну и ту же функцию
 

phprus

Moderator
Команда форума
Андрейка
Интерпретация важна при преобразовании типа. (char -> int). в данном случае, так как оба типа знаковые и int больше char'а. Так как оба типа знаковые, то е единичек char будут преобразованы в 32 единички int, так как и там и там так представлено число -1
 

kruglov

Новичок
phprus
Так, подождите, а EOF чему равен в char? И чему равен код "я" в char? Чтобы они преобразовывались в разные intы?
 

phprus

Moderator
Команда форума
kruglov
Так, подождите, а EOF чему равен в char?
Я просмотрел всю функцию str_word_count и в ней нигде нет сравнения символа с EOF. Библиотечная функция isalpha принимает параметр типа int и по этому внутри нее EOF сравнивается с int'ом, а в инте -1 и 255 - это разные числа. Именно по этому единственное место где тут возможна проблема - это преобразование char в int (при передаче параметра в функцию isalpha). Именно в этом месте мы получаем -1 вместо 255.
 

baev

‹°°¬•
Команда форума
GrayHound, ОС какая?

И покажите небольшой пример кода.
 

Farsh

~ on ~ high ~ wave ~
Блин , народ , кто нибудь смог нормально использовать str_word_count с русским языком ?
Что только не перепробовал , белеберду выдает .
Или есть ли у кого нибудь нормальная , несырая функция для подсчета слов в тексте ?
 

tony2001

TeaM PHPClub
Farsh
локаль установи правильную.

phprus
протестировать своё предположение насчет unsigned char можешь?
у меня нет локали cp1251.
 

phprus

Moderator
Команда форума
Тестовый код:
PHP:
<?php
var_dump(setlocale(LC_ALL, 'ru_RU.cp-1251', 'ru_RU.CP1251'));
var_dump(str_word_count('русский текст. я тестер. аябаг. яап. авя', 2));
?>
1) До изменения исходников результат:
Код:
string(12) "ru_RU.CP1251"
array(7) {
  [0]=>
  string(7) "русский"
  [8]=>
  string(5) "текст"
  [17]=>
  string(6) "тестер"
  [25]=>
  string(1) "а"
  [27]=>
  string(3) "баг"
  [33]=>
  string(2) "ап"
  [37]=>
  string(2) "ав"
}
Вывод: Баг есть.

2) После изменения исходников результат:
Код:
string(12) "ru_RU.CP1251"
array(7) {
  [0]=>
  string(7) "русский"
  [8]=>
  string(5) "текст"
  [15]=>
  string(1) "я"
  [17]=>
  string(6) "тестер"
  [25]=>
  string(5) "аябаг"
  [32]=>
  string(3) "яап"
  [37]=>
  string(3) "авя"
}
Вывод: вроде бы бага нет.

Что я изменял написано в моем первом сообщении в этой теме.

P.S. У меня тоже небыло локали cp1251. Пришлось поставить для тестов.
 

phprus

Moderator
Команда форума
tony2001
Вот баг: http://bugs.php.net/bug.php?id=43863

Русские буквы благополучно побились благодаря тому что эта система оборудована "защитой" от спама(честных пользователей) в виде вывода сообщений о том что вам неплохо было бы и поискать по нашей базе перед тем как баг постить. Все бы было ничего если бы при выводе этого сообщения не портились все не английские буквы в полях описания.
 
Сверху