Все это выполняется при условии, что вы используете кодировку UTF-8.
Вы можете использовать наивный подход, используя preg_split()
, чтобы разделить строку на любой разделитель. , знак препинания или управляющий символ.
preg_split
пример:
$split = preg_split('/[\pZ\pP\pC]/u', $string, -1, PREG_SPLIT_NO_EMPTY);
print_r(array_count_values($split));
Выход:
Array
(
[This] => 1
[is] => 1
[just] => 1
[a] => 1
[test] => 1
[post] => 1
[with] => 1
[the] => 1
[Swedish] => 1
[characters] => 2
[Å] => 1
[Ä] => 1
[and] => 2
[Ö] => 1
[Also] => 1
[as] => 1
[lower] => 1
[cased] => 1
[å] => 1
[ä] => 1
[ö] => 1
)
Это отлично работает для заданной строки, но не обязательно разделяет слова таким образом, чтобы учитывать локаль. Например, такие сокращения, как «isn't», будут разбиты на «isn» и «t».
К счастью, расширение Intl добавляет множество функций для работы с подобными вещами в PHP 7.
План будет заключаться в следующем:
*Нормализуйте ввод с помощью Normalizer::normalize()
, чтобы убедиться, что все графемы закодированы согласованным образом. Например, ä
может быть закодировано и, следовательно, подсчитано двумя способами:
- U+00E4 'LATIN SMALL LETTER A WITH DIAERESIS' or
- U + 0061 «ЛАТИНСКАЯ СТРОЧНАЯ БУКВА A», за которой следует U + 0308 «КОМБИНИРОВАНИЕ ДИЭРЕЗИСА»
Получите IntlBreakIterator
, который разбивает слова в зависимости от локали через IntlBreakIterator::createWordInstance()
. Это понимает, что составляет «слово» для данной локали, включая обработку сокращений, таких как «не».
Получите его IntlPartsIterator
через IntlBreakIterator::getPartsIterator()
для простоты повторения текстовых фрагментов.
Пропускайте то, что вам не нужно, с помощью IntlChar::ispunct()
и IntlChar::isspace()
(*Обратите внимание, что вы, вероятно, захотите выполнить нормализацию независимо от того, какой метод вы используете для разбиения строки — это было бы уместно сделать перед preg_split
выше или любым другим способом, который вы решите использовать.)
Международный пример:
$string = Normalizer::normalize($string);
$iter = IntlBreakIterator::createWordInstance("sv_SE");
$iter->setText($string);
$words = $iter->getPartsIterator();
$split = [];
foreach ($words as $word) {
// skip text fragments consisting only of a space or punctuation character
if (IntlChar::isspace($word) || IntlChar::ispunct($word)) {
continue;
}
$split[] = $word;
}
print_r(array_count_values($split));
Выход:
Array
(
[This] => 1
[is] => 1
[just] => 1
[a] => 1
[test] => 1
[post] => 1
[with] => 1
[the] => 1
[Swedish] => 1
[characters] => 2
[Å] => 1
[Ä] => 1
[and] => 2
[Ö] => 1
[Also] => 1
[as] => 1
[lower] => 1
[cased] => 1
[å] => 1
[ä] => 1
[ö] => 1
)
Это более подробно, но может оказаться полезным, если вы предпочитаете ICU (библиотека, поддерживающая расширение Intl) делать тяжелую работу, когда дело доходит до понимания того, из чего состоит слово.
person
user3942918
schedule
24.09.2016
str
, не является безопасной для нескольких байтов. Комментарии пользователей в руководстве предлагают альтернативы. - person CBroe   schedule 24.09.2016...PHP function with a name starting with str...
где эта функция? - person SaidbakR   schedule 24.09.2016mb_str_word_count
вместоstr_word_count
: stackoverflow.com/a/17725577/6797531 - person CatalinB   schedule 24.09.2016Array([This is just a test post with the Swedish characters �, �, and Ö. Also as lower cased characters: �, �, and �.] => 1)
- person Airikr   schedule 24.09.2016