«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.