Создание эффективного счетчика слов, включая китайский/японский и другие языки с акцентом

После попытки выяснить, как иметь эффективный счетчик слов в строке, я знаю о существующей функции, которая есть в PHP str_word_count но, к сожалению, он не делает того, что мне нужно, потому что мне нужно будет подсчитать количество слов, включающих английские, китайские, японские и другие символы с диакритическими знаками.

Однако str_word_count не может подсчитать количество слов, если вы не добавите символы в третьем аргументе, но это безумие, это может означать, что мне нужно добавить каждый отдельный символ в китайских, японских, акцентированных символах (и т. д. ) язык, но это не то, что мне нужно.

Тесты:

str_word_count('The best tool'); // int(3)
str_word_count('最適なツール'); // int(0)
str_word_count('最適なツール', 0, '最ル'); // int(5)

Во всяком случае, я нашел эту функцию в Интернете, она может работать, но, к сожалению, она не учитывается:

function word_count($str)
{
    if($str === '')
    {
        return 0;
    }

    return preg_match_all("/\p{L}[\p{L}\p{Mn}\p{Pd}'\x{2019}]*/u", $str);
}

Тесты:

word_count('The best tool') // int(3)
word_count('最適なツール'); // int(1)

// With spaces
word_count('最 適 な ツ ー ル'); // int(5)

В основном я ищу хороший счетчик слов с поддержкой UTF-8, который может подсчитывать слова из каждого типичного слова/символа с акцентом/языка - есть ли возможное решение для этого?


person MacMac    schedule 18.06.2012    source источник
comment
Языки подсчета слов, в которых не используются пробелы, представляют собой сложную проблему, и в основном ее можно решить только с помощью словаря и алгоритма, настроенного для этого конкретного языка. PHP не имеет ничего подобного встроенного, и вам даже может быть трудно найти такую ​​библиотеку, написанную на PHP.   -  person deceze♦    schedule 18.06.2012


Ответы (3)


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

mb_split() разбивает строку mb, используя шаблон регулярного выражения.

<?php 
printf("Counting words in: %s\n", $argv[1]);
mb_regex_encoding('UTF-8');
mb_internal_encoding("UTF-8");
$r = mb_split(' ', $argv[1]); 
print_r($r); 
printf("Word count: %d\n", count($r));

$ php mb.php "foo bar"
Counting words in: foo bar
Array
(
    [0] => foo
    [1] => bar
)
Word count: 2


$ php mb.php "最適な ツール"
Counting words in: 最適な ツール
Array
(
    [0] => 最適な 
    [1] => ツール
)
Word count: 2

Примечание. Мне пришлось добавить 2 пробела между символами, чтобы получить правильный счет Исправлено путем установки mb_regex_encoding() и mb_internal_encoding() на UTF-8

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

Возможно, вам придется написать алгоритм с использованием словаря, чтобы определить, какие группы символов являются «словом».

person Boris Guéry    schedule 18.06.2012
comment
Мне пришлось добавить 2 пробела... - Ну да, это именно та проблема, которую пытается решить ОП. А в японском обычно пробелов нет. -1 - person deceze♦; 18.06.2012
comment
@deceze, удвоение количества пробелов не проблема, однако это было решено путем установки mb_regex_encoding() и mb_internal_encoding() в UTF-8 - person Boris Guéry; 18.06.2012
comment
UTF-8 не имеет никакого отношения к рассматриваемой проблеме. Проблема в том, что в японском (и других языках) нет разделителей слов, так что вы не можете просто mb_split его использовать. - person deceze♦; 18.06.2012
comment
@deceze, ты прочитал текст, выделенный жирным шрифтом? Функция предполагает, что слово представляет собой группу символов, разделенных пробелом. Он не предназначен для семантического подсчета слов. - person Boris Guéry; 18.06.2012

Существует морфологический анализатор Куромодзи для японского языка, который можно использовать для подсчета слов. К сожалению, он написан на Java, а не на PHP. Поскольку портирование всего этого на PHP является довольно сложной задачей, я бы предложил написать вокруг него небольшую оболочку, чтобы вы могли вызывать ее в командной строке или изучать другие мосты PHP-Java.

Я не знаю, насколько это применимо к другим языкам, кроме японского. Вы можете изучить проект Apache Tika, чтобы найти подобные библиотеки.

person deceze♦    schedule 18.06.2012

У меня были хорошие результаты с использованием итератора break расширения Intl, который размечает строки, используя границы слов с учетом локали. например:

<?php
$words = IntlBreakIterator::createWordInstance('zh');
$words->setText('最適なツール');

$count = 0;
foreach( $words as $offset ){
  if( IntlBreakIterator::WORD_NONE !== $words->getRuleStatus() ){
    $count++;
  }
}

printf("%u words", $count ); // 3 words

Поскольку я не понимаю китайский язык, я не могу проверить, что "3" является правильным ответом. Тем не менее, он дает точные результаты для сценариев, которые я понимаю, и я верю, что библиотека ICU надежна.

Я также отмечаю, что передача параметра «zh», кажется, не влияет на результат, но аргумент является обязательным.

Я использую Intl PECL-3.0.0 и версию ICU 55.1. Я обнаружил, что мои серверы CentOS работают под управлением более старых версий, чем эти, и они не работают для китайского языка. Поэтому убедитесь, что у вас установлены последние версии.

person Tim    schedule 16.09.2016