«1. Обзор

В этом уроке мы рассмотрим различные способы подсчета слов в заданной строке с использованием Java.

2. Использование StringTokenizer

Простой способ подсчета слов в строке в Java — это использование класса StringTokenizer:

assertEquals(3, new StringTokenizer("three blind mice").countTokens());
assertEquals(4, new StringTokenizer("see\thow\tthey\trun").countTokens());

Обратите внимание, что StringTokenizer автоматически позаботится о пробелах, таких как табуляция и возврат каретки. .

Но в некоторых местах это может быть нелепо, например, в дефисах:

assertEquals(7, new StringTokenizer("the farmer's wife--she was from Albuquerque").countTokens());

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

К счастью, StringTokenizer поставляется с другим конструктором. Мы можем передать разделитель в конструктор, чтобы заставить вышеприведенное работать: просто, и это доводит нас до конца.

assertEquals(7, new StringTokenizer("the farmer's wife--she was from Albuquerque", " -").countTokens());

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

assertEquals(10, new StringTokenizer("did,you,ever,see,such,a,sight,in,your,life", ",").countTokens());

3. Регулярные выражения

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

Имея это в виду, нам нужно разбить эту строку в каждой точке, где мы встречаем пробелы и знаки препинания, а затем подсчитать получившиеся слова.

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

Нецелесообразно решать эту задачу, просто передавая разделитель в StringTokenizer, поскольку нам пришлось бы определять очень длинный разделитель, чтобы попытаться перечислить все возможные знаки препинания.

assertEquals(7, countWordsUsingRegex("the farmer's wife--she was from Albuquerque"));

Оказывается, нам действительно не нужно много делать, передача регулярного выражения [\\pP\\s\u0026\u0026[^’]]+ методу split класса String сделает свое дело:

assertEquals(9, countWordsUsingRegex("no&one#should%ever-write-like,this;but:well"));

регулярное выражение [\\pP\\s\u0026\u0026[^’]]+ находит любую длину знаков препинания или пробелов и игнорирует знак препинания в виде апострофа.

Чтобы узнать больше о регулярных выражениях, обратитесь к разделу «Регулярные выражения» на сайте Baeldung.

public static int countWordsUsingRegex(String arg) {
    if (arg == null) {
        return 0;
    }
    final String[] words = arg.split("[\pP\s&&[^']]+");
    return words.length;
}

4. Циклы и String API

Другой метод заключается в наличии флага, который отслеживает встречающиеся слова.

Мы устанавливаем флаг в СЛОВО при встрече с новым словом и увеличиваем количество слов, а затем возвращаемся к СЕПАРАТОРУ, когда встречаем не слово (знаки препинания или пробелы).

Этот подход дает нам те же результаты, что и с регулярными выражениями:

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

Что мы хотим здесь считать «фермерский» как одно слово, хотя апостроф «» — это знак препинания.

assertEquals(9, countWordsManually("no&one#should%ever-write-like,this but   well"));

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

assertEquals(6, countWordsManually("the farmer's wife--she was from Albuquerque"));

Теперь мы можем использовать этот метод в нашей реализации:

Первое условие помечает слово при его встрече и увеличивает счетчик. Второе условие проверяет, не является ли символ буквой, и устанавливает флаг в SEPARATOR.

private static boolean isAllowedInWord(char charAt) {
    return charAt == '\'' || Character.isLetter(charAt);
}

5. Заключение

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

public static int countWordsManually(String arg) {
    if (arg == null) {
        return 0;
    }
    int flag = SEPARATOR;
    int count = 0;
    int stringLength = arg.length();
    int characterCounter = 0;

    while (characterCounter < stringLength) {
        if (isAllowedInWord(arg.charAt(characterCounter)) && flag == SEPARATOR) {
            flag = WORD;
            count++;
        } else if (!isAllowedInWord(arg.charAt(characterCounter))) {
            flag = SEPARATOR;
        }
        characterCounter++;
    }
    return count;
}

Как обычно, исходный код этого руководства можно найти на GitHub.

«

In this tutorial, we have looked at ways to count words using several approaches. We can pick any depending on our particular use-case.

As usual, the source code for this tutorial can be found over on GitHub.