Получить количество слов из строки в Юникоде (на любом языке)


Я хочу получить количество слов из строки. Это так просто, как это. Загвоздка в том, что строка может быть на непредсказуемом языке.

Итак, мне нужна функция сигнатуры int getWordCount(String) со следующим образцом вывода -

getWordCount("供应商代发发货") => 7
getWordCount("This is a sentence") => 4

Любая помощь о том, как действовать, будет оценена:)

5 7

5 ответов:

Понятие "слово" может быть тривиальным или сложным. ВотApache Stanbol Toolkit:

Маркировка слов: обнаружение одиночных слов требуется для Stanbol Enhancer для обработки текста. Хотя для большинства это тривиально языки это довольно сложная задача для некоторых восточных языков, напр. Китайский, Японский, Корейский. Если не настроено иначе, то Stanbol будет используйте пробелы для обозначения слов.

Так что если понятие слова лингвистическое, то скорее вместо синтаксического, вы должны использовать инструментарий NLP

Мое предпочтительное решение Java-это открытое NLP Apache

Примечание: Я использовал http://www.mdbg.net/chindict/chindict.php?page=worddict чтобы обозначить ваш пример. Это означает, что есть 4 слова, а не семь. Я вырезал и наклеил (довольно фрагментарно):

Оригинальный Текст Упрощен Pīnyīn Английское определение добавьте новое слово в словарь традиционный HSK 供应商 供应商 gōngyìngshāng

Поставщик

供應商 代
代 dài

Заменить / действовать от имени других / заменить / поколение / династию / век / период / (историческую) эру / (геологическую) Эон


发 fā

Разослать / показать (свое чувство) / выдать / разработать / классификатор для выстрелов (патронов)

發 HSK 4

发 fà

Hair / Taiwan pr. [fa3]

髮 发货
发货 fāhuò

Для отправки / для отправки товары

發貨

Эти первые три символа, по-видимому, образуют одно слово.

Стандартный API предоставляетBreakIterator для такого рода граничного анализа, но поддержка языка Oracle Java 7 не нарушает строку образца.

Когда я использовал ICU4J v51. 1 BreakIterator, он разбил образец на [供应, 商代, 发, 发, 货].

// import com.ibm.icu.text.BreakIterator;
String sentence = "\u4f9b\u5e94\u5546\u4ee3\u53d1\u53d1\u8d27";
BreakIterator iterator = BreakIterator.getWordInstance(Locale.CHINESE);
iterator.setText(sentence);

List<String> words = new ArrayList<>();
int start = iterator.first();
int end = iterator.next();
while (end != BreakIterator.DONE) {
  words.add(sentence.substring(start, end));
  start = end;
  end = iterator.next();
}
System.out.println(words);

Примечание: я использовал Google Translate, чтобы догадаться, что "供应商代发发货" было китайским. Очевидно, я не говорю на этом языке, поэтому не могу прокомментировать правильность вывода.

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

    public String separatorForLanguage(char unicodeChar){
        // Find out in which language unicodeChar falls  
        return ""; // return regex of separator of that language
    }

    public int wordCount(String sentance){
        char unicodeChar = sentance.charAt(0);
        String separator = separatorForLanguage(unicodeChar);

        int count = sentance.split(separator).length;
        if (separator.isEmpty()) {
            count--;
        }

        return count;
    }

Вот фрагмент в java

public static int getWordCount(String string)
{
    Pattern pattern = Pattern.compile("[\\w']+|[\\u3400-\\u4DB5\\u4E00-\\u9FCC]");
    Matcher matcher = pattern.matcher(string);
    int count = 0;
    while(matcher.find())
        count++;
    return count;                                   
}

Пример

//count is 5
int wordCount = getWordCount("this is popcorny's 電腦");

Английская версия

Для английской версии можно обойтись довольно простым регулярным выражением. Возможно, я пропустил некоторые пользовательские разделители, но:

public static int getWordCount(String str) {
    return str.split("[\\s,;-]+").length;
}

Объяснение регулярных выражений:

Разделить, если найдется в группе []:

[
\\s Any whitespace character or
, A comma
; or a semi-colon
]
+ Followed by any patterns in the group any number of times

Китайская версия

Для китайской версии вам нужно определить, что такое разделители. Если вы получите Unicode char код китайских разделителей и добавите их к приведенному выше регулярному выражению, вы получите желаемое результаты.

Тесты

System.out.println(getWordCount("This is a sentence"));// 4
System.out.println(getWordCount("This is a sentence")); // 4
System.out.println(getWordCount("This is a     ,,sentence")); // 4