Использование метода split() для большого текстового файла

У меня есть огромный файл можно сказать книга, и я хочу сделать split чтоб смог посчитать сколько раз каждое слово встречается в файле. Но непонятно как использовать метод split(), потому что в тексте огромное количество знаков пробелов. Это не помогает String[] words = line.split(" ");

 BufferedReader br = new BufferedReader(new FileReader("D:\\customer1.txt"))) {
                StringBuilder sb = new StringBuilder();
                String line = br.readLine().toLowerCase(); 
String[] words = line.split(" ");

Ответы (2 шт):

Автор решения: Yan Wolf

Я в java не силен, но возможно вы сможете найти ответ на примере Python кода:

from collections import defaultdict

with open("text.txt") as file_book:
    for line in file_book:
        words = line
        
word_list = words.split()

word_count_dict = defaultdict(int) 

for word in word_list:
    word_count_dict[word] += 1
    print(word, word_count_dict[word])
→ Ссылка
Автор решения: Alex Rudenko

Во-первых, String::split помогает.

Во-вторых, для исключения нескольких пробельных символов, идущих подряд, следует использовать регулярное выражение .split("\\s+"), однако оно не исключает знаки пунктуации, которые будут включаться в слова. Можно применять разбиение по другим POSIX-классам символов:

  • .split("\\P{L}+") - разбить по всем символам, не являющимся буквами (\\P - отрицание)
  • .split("\\P{Alnum}+") - разбить по всем символам, не являющимися буквами или цифрами
  • .split("[\\p{Space}\\p{Punct}]+") - разбить по всем символам, являющимися пробельными символами или знаками пунктуации

В-третьих, для подсчета частоты слов следует использовать словарь/хэш-таблицу слов Map<String, Long>, где слово является ключом, частота -- значением.

Используя NIO API для чтения файлов и Java Stream API, можно написать такую реализацию:

public static Map<String, Long> wordFreqMap(String filename) throws IOException {
    return Files.lines(Paths.get(filename)) // Stream<String> - поток строк
        .map(line -> line.split("\\P{Alnum}+"))   // Stream<String[]> - массивы слов
        .flatMap(Arrays::stream) // Stream<String> - поток слов
        .collect(Collectors.groupingBy(
            word -> word,          // сгруппировать по ключам-словам
            Collectors.counting()  // подсчитать частоту
        ));
}

Операции .map + flatMap можно объединить в одну:

    return Files.lines(Paths.get(filename)) // Stream<String> - поток строк
        .flatMap(line -> Arrays.stream(line.split("\\P{Alnum}+")))
// ...
→ Ссылка