Intereting Posts
Как использовать строку PHP в запросе mySQL LIKE? Моделирование типов с помощью UML на основе ассоциативных массивов Загрузка файла Blueimp jQuery, передача данных дополнительной формы Выберите все параметры в Ошибка синтаксиса PHP T_ENCAPSED_AND_WHITESPACE не удалось сортировать дату, используя usort кэширование статических данных в PHP с помощью opcache Использование двойных кавычек в значении 'input type = "text"' не работает, строка останавливается при двойной кавычке! Laravel скачать файл с S3 маршрута (не открыть в браузере) Как добавить пользовательские правила валидации при использовании проверки формы запроса в Laravel 5 Как исправить тайм-аут соединения cURL SSL, который происходит только при первом вызове сценария Как отслеживать по номеру отслеживания уникальный идентификатор? Удалить index.php из codeigniter в подпапке Настройка хранилища конфигурации Проблемы с проверкой наличия или отсутствия таблицы в db

это PHP str_word_count () многобайтовый сейф?

Я хочу использовать str_word_count() в строке UTF-8.

Это безопасно в PHP? Мне кажется, что это должно быть (особенно учитывая, что нет mb_str_word_count() ).

Но на php.net много людей путают воду, представляя свои собственные «многобайтовые совместимые» версии функции .

Поэтому, я думаю, я хочу знать …

  1. Учитывая, что str_word_count просто подсчитывает все последовательности символов в разделителе " " (пробел), он должен быть безопасным для многобайтовых строк, даже если он не обязательно знает о символьных последовательностях, верно?

  2. Существуют ли в UTF-8 эквивалентные «пробельные» символы, которые не являются ASCII " " (пробелом)? #

Я думаю, что проблема может оказаться ложной.

Я бы сказал, вы правильно поняли. И действительно, в UTF-8 есть пробелы, которые не являются частью US-ASCII. Чтобы дать вам пример таких пространств:

  • Unicode-символ «NO-BREAK SPACE» (U + 00A0) : 2 байта в UTF-8: 0xC2 0xA0 (c2a0)

И, возможно, также:

  • Unicode Character 'NEXT LINE (NEL)' (U + 0085) : 2 байта в UTF-8: 0xC2 0x85 (c285)
  • Юникодный символ «LINE SEPARATOR» (U + 2028) : 3 байта в UTF-8: 0xE2 0x80 0xA8 (e280a8)
  • Unicode Character «PARAGRAPH SEPARATOR» (U + 2029) : 3 байта в UTF-8: 0xE2 0x80 0xA8 (e280a8)

Во всяком случае, первый – «NO-BREAK SPACE» (U + 00A0) – хороший пример, так как он также является частью кодировок Latin-X. В руководстве по PHP уже содержится подсказка, что str_word_count будет зависящим от языка.

Если мы хотим поставить это на тест, мы можем установить языковой стандарт в UTF-8, передать недопустимую строку, содержащую последовательность \xA0 , и если это все еще считается символом прерывания слова, эта функция явно не является безопасным для UTF-8 , следовательно, не многобайтовый сейф (такой же, который не определен в вопросе):

 <?php /** * is PHP str_word_count() multibyte safe? * @link https://stackoverflow.com/q/8290537/367456 */ echo 'New Locale: ', setlocale(LC_ALL, 'en_US.utf8'), "\n\n"; $test = "aword\xA0bword aword"; $result = str_word_count($test, 2); var_dump($result); 

Вывод:

 New Locale: en_US.utf8 array(3) { [0]=> string(5) "aword" [6]=> string(5) "bword" [12]=> string(5) "aword" } 

Как показывает эта демонстрация , эта функция полностью терпит неудачу в отношении языкового обещания, которое она дает на странице руководства (я не удивляюсь и не стонать об этом, чаще всего, если вы читаете, что функция является языковой спецификой в ​​PHP, запускайте свою жизнь и находите ее это не так), который я использую здесь, чтобы продемонстрировать, что он никоим образом не делает ничего относительно кодировки символов UTF-8.

Вместо этого для UTF-8 вы должны заглянуть в расширение PCRE:

  • Соответствие символов символов Unicode в PCRE / PHP

PCRE хорошо разбирается в Unicode и UTF-8 в PHP. Он также может быть довольно быстрым, если вы тщательно продутируете шаблон регулярного выражения.

Об «шаблоне ответа» – я не получаю требование «работать быстрее». Мы не говорим о долгих временах или о многом подсчетах, так что кому это нужно, если это займет несколько миллисекунд дольше или нет?

Однако str_word_count работает с мягким дефис:

 function my_word_count($str) { return str_word_count(str_replace("\xC2\xAD",'', $str)); } 

функция, которая соответствует утверждениям (но, вероятно, не быстрее str_word_count):

 function my_word_count($str) { $mystr = str_replace("\xC2\xAD",'', $str); // soft hyphen encoded in UTF-8 return preg_match_all('~[\p{L}\'\-]+~u', $mystr); // regex expecting UTF-8 } 

Функция preg по существу является тем же, что и было предложено, за исключением того, что a) она уже возвращает счет, поэтому нет необходимости поставлять совпадения, что должно ускорить ее выполнение и b) на самом деле не должно быть резервного копирования iconv, IMO.


Оставить комментарий:

Я вижу, что ваши функции PCRE являются wrost (производительность), чем мой preg_word_count (), потому что вам нужно str_replace, которое вам не нужно: '~ [^ \ p {L} \' – \ xC2 \ xAD] + ~ u работает отлично ( !).

Я считал, что другая вещь , замените строку, удалит только многобайтовый символ, но ваше регулярное выражение будет иметь дело с \\xC2 и \\xAD в любом порядке, который может появиться, что неверно. Рассмотрим зарегистрированный знак , который является \ xC2 \ xAE.

Однако теперь, когда я думаю об этом из-за того, как работает действительный UTF-8, это не имеет большого значения, поэтому его следует использовать одинаково хорошо. Таким образом, мы можем просто иметь функцию

 function my_word_count($str) { return preg_match_all('~[\p{L}\'\-\xC2\xAD]+~u', $str); // regex expecting UTF-8 } 

без необходимости в матчах или других заменах.

О str_word_count (str_replace ("\ xC2 \ xAD", '', $ str)) ;, если он стабилен с UTF8, это хорошо, но, похоже, это не так .

Если вы прочитаете этот поток , вы узнаете, что str_replace безопасен, если вы придерживаетесь действительных строк UTF-8. Я не видел никаких доказательств в вашей ссылке об обратном.

EDITED (чтобы показать новые подсказки): существует возможное решение с использованием str_word_count() с PHP v5.1!

 function my_word_count($str, $myLangChars="àáãâçêéíîóõôúÀÁÃÂÇÊÉÍÎÓÕÔÚ") { return str_word_count($str, 0, $myLangChars); } 

но не 100%, потому что я пытаюсь добавить в $ myLangChars \xC2\xAD ( символ SHY – SOFT HYPHEN ), который должен быть компонентом слова на любом языке, и он не работает ( см. ).

Другое, не очень быстрое, но полное и гибкое решение (извлеченное отсюда) , основанное на библиотеке PCRE, но с возможностью имитировать поведение str_word_count() для недействительных UTF8:

  /** * Like str_word_count() but showing how preg can do the same. * This function is most flexible but not faster than str_word_count. * @param $wRgx the "word regular expression" as defined by user. * @param $triggError changes behaviour causing error event. * @param $OnBadUtfTryAgain when true mimic the str_word_count behaviour. * @return 0 or positive integer as word-count, negative as PCRE error. */ function preg_word_count($s,$wRgx='/[-\'\p{L}\xC2\xAD]+/u', $triggError=true, $OnBadUtfTryAgain=true) { if ( preg_match_all($wRgx,$s,$m) !== false ) return count($m[0]); else { $lastError = preg_last_error(); $chkUtf8 = ($lastError==PREG_BAD_UTF8_ERROR); if ($OnBadUtfTryAgain && $chkUtf8) return preg_word_count( iconv('CP1252','UTF-8',$s), $wRgx, $triggError, false ); elseif ($triggError) trigger_error( $chkUtf8? 'non-UTF8 input!': "error PCRE_code-$lastError", E_USER_NOTICE ); return -$lastError; } } 

(ШАБЛОННЫЙ ОТВЕТ) помощь за щедрость!

(это не ответ, это помощь за щедрость , потому что я не могу редактировать ни дублировать вопрос)

Мы хотим считать «реальные слова» в латиматическом тексте UTF-8.

ДЛЯ БОУНТА, НУЖНО:

  • функция, которая соответствует assert s ниже и быстрее, чем str_word_count ;
  • или str_word_count работающий с символом SHY (как?);
  • или preg_word_count работает быстрее (используя регулярное выражение word-separator preg_replace?).

УТВЕРЖДАЕТ

Предположим, что существует функция « my_word_count() safe» my_word_count() , тогда должны быть утверждены следующие утверждения:

 assert_options(ASSERT_ACTIVE, 1); $text = "1,2,3,4=0 (1 2 3 4)=0 (... ,.)=0 (2.5±0.1; 0.5±0.2)=0"; assert( my_word_count($text)==0 ); // no word there $text = "(one two,three;four)=4 (five-six se\xC2\xADven)=2"; assert( my_word_count($text)==6 ); // hyphen merges two words $text = "(um±dois três)=3 (àáãâçêéíîóõôúÀÁÃÂÇÊÉÍÎÓÕÔÚ)=1"; assert( my_word_count($text)==4 ); // a UTF8 case $text = "(ÍSÔ9000-X, ISÔ 9000-X, ÍSÔ-9000-X)=6"; //Codes are words? assert( my_word_count($text)==6 ); // suppose no: X is another word 

Все это подсчитывает количество пробелов или слов между ними. если вам интересно, вы можете просто сделать свою собственную функцию подсчета с помощью взрыва и подсчета.

В любое время, когда найден байт ascii, он разбивается и все на самом деле.