Java рассчитывая # случаев слова в строке

У меня есть файл крупного текста, из которого я читаю, и я должен узнать, сколько раз подходят некоторые слова. Например, слово the. Я делаю это линию за линией, каждая строка является строкой.

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

numSpace += line.split("[^a-z]the[^a-z]").length;  

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

Обновление: Данный некоторое представление, я придумал это:

numThe += line.split("[^a-zA-Z][Tt]he[^a-zA-Z]", -1).length - 1;

Все еще получая некоторые странные числа. Я смог получить точное общее количество (без регулярного выражения), теперь моя проблема с regexp.

5
задан Alan Moore 14 April 2010 в 12:03
поделиться

6 ответов

Использование split для подсчета не является самым эффективным, но если вы настаиваете на этом, то правильный способ такой:

haystack.split(needle, -1).length -1                            

Если вы не установите limit на -1 , split по умолчанию будет иметь значение 0 , что удаляет завершающие пустые строки, что беспорядочно подсчитайте.

Из API :

Параметр limit управляет количеством применений шаблона и, следовательно, влияет на длину результирующего массива. [...] Если n равно нулю, то [...] завершающие пустые строки будут отброшены.

Вам также необходимо вычесть 1 из длины массива, поскольку N вхождений разделителя разбивает строку на N + 1 частей.


Что касается самого регулярного выражения (то есть иглы ), вы можете использовать \ b привязку границы слова вокруг слова . Если вы разрешаете word содержать метасимволы (например, подсчитывать количество вхождений «$ US» ), вы можете захотеть Pattern.quote его.


Я придумал это:

 numThe + = line.split ("[^ a-zA-Z] [Tt] he [^ a-zA-Z]", -1) .length - 1; 
 

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

Теперь проблема в том, что вы не учитываете [Tt] he , которое появляется как первое или последнее слово, потому что регулярное выражение говорит, что ему должен предшествовать / за ним должен идти какой-то символ, что-то, что соответствует [^ a-zA-Z] (то есть ваше совпадение должно иметь длину 5!). Вы не допускаете случая, когда не является персонажем!

Вместо этого вы можете попробовать что-нибудь вроде этого:

"(^|[^a-zA-Z])[Tt]he([^a-zA-Z]|$)"

Это не самое краткое решение, но оно работает.

Что-то вроде этого (с использованием отрицательного поиска ) также работает:

"(?<![a-zA-Z])[Tt]he(?![^a-zA-Z])"

Это дает преимущество сопоставления только [Tt] he , без каких-либо дополнительных символы вокруг него, как и в предыдущем решении. Это актуально в том случае, если вы действительно хотите обработать токены, возвращенные split , потому что разделитель в этом случае ничего не «крадет» из токенов.


Не- разбиение

Хотя использование разбиения для подсчета довольно удобно, это не самый эффективный способ (например,он выполняет всевозможную работу, чтобы вернуть те строки, которые вы отбрасываете). Тот факт, что, как вы сказали, вы считаете строку за строкой, означает, что шаблон также придется перекомпилировать и отбрасывать каждую строку.

Более эффективным способом было бы использовать то же регулярное выражение, которое вы использовали ранее, и выполнить обычные Pattern.compile и while (matcher.find ()) count ++;

9
ответ дан 18 December 2019 в 07:08
поделиться

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

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

4
ответ дан 18 December 2019 в 07:08
поделиться

Вы можете попробовать использовать границу слова \ b в регулярное выражение:

\bthe\b

Также размер массива, возвращаемого разделением , будет на 1 больше, чем фактическое количество вхождений слова the в строке .

1
ответ дан 18 December 2019 в 07:08
поделиться

Найдите «the», используя boyer-moore [в оставшейся части строки после hit] и подсчитать количество повторов?

0
ответ дан 18 December 2019 в 07:08
поделиться

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

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

2
ответ дан 18 December 2019 в 07:08
поделиться

Разделение строк звучит как много накладных расходов только для того, чтобы узнать количество вхождений в файл. Вы можете использовать String.indexOf (String, int) для рекурсивного просмотра всей строки / файла, например:

int occurrences = 0;
int index = 0;
while (index < s.length() && (index = s.indexOf("the", index)) >= 0) {
    occurrences++;
    index + 3; //length of 'the'
}
4
ответ дан 18 December 2019 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: