Java: подсчет вхождения слов, программа считает «пустые» слова - PullRequest
0 голосов
/ 13 марта 2020

У меня есть программа, которая берет ввод из текстового файла, удаляет пунктуацию, а затем разделяет на один пробел и подсчитывает результаты в карту. Я могу заставить его работать, но я получаю пустой результат на карте, и я не знаю, что дает:

Сканер принимает:

try
        {
            Scanner input = new Scanner(file);
            String nextLine;
            while (input.hasNextLine())
            {
                nextLine = input.nextLine().trim();
                processLine(nextLine, occurrenceMap);
            }
            input.close();
        }
        catch(Exception e) { System.out.println("Something has gone wrong!");}

Текстовый файл то, что он извлекает из Библии, является королем Джеймсом, затем каждая строка обрабатывает отдельную функцию:

//String[] words = line.replaceAll("[^a-zA-Z0-9 ]", " ").toLowerCase().split("\\s+"); // runtime for  bible.txt is ~1600ms

// changed to simple iteration and the program ran MUCH faster:

char[] letters = line.trim().toCharArray();
for (int i=0; i<letters.length; i++)
{
    if (Character.isLetterOrDigit(letters[i])) {continue;}
    else {letters[i] = ' ';}
}

String punctuationFree = new String(letters);
String[] words = punctuationFree.toLowerCase().split("\\W+");

// add each word to the frequency map:
for (int i=0; i<words.length; i++)
{
    if (! map.containsKey(words[i]))
    {
        map.put(words[i], 1);
    }
    else
    {
        int value = (int)map.get(words[i]);
        map.put(words[i], ++value);
    }
}

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

num occurences/ (number /word)

25307 :     // what is up with this empty value ?
1 : 000     // the results continue in sorted order
2830 : 1
2122 : 10
6 : 100
9 : 101
29 : 102
23 : 103
36 : 104
46 : 105
49 : 106

Я пытался изменить String[] words = punctuationFree.toLowerCase().split("\\W+"); на .split ("\ s +") и .split ( "") но я все еще получаю это пустое значение в результатах.

Я пытаюсь подсчитывать только вхождения слов и цифр, почему я получаю это пустое значение?

ОБНОВЛЕНИЕ: при предположении, что Character.isLetterOrDi git () может возвращать нежелательные символы я переписал чеки, чтобы получить только те символы, которые я хочу. Тем не менее, я все еще получаю загадочное пустое значение:

for (int i=0; i<letters.length; i++)
    {
        if ((letters[i] >= 'a' && letters[i] <= 'z') || 
           (letters[i] >= 'A' && letters[i] <= 'Z'))
           {continue;}
        else if (letters[i] >= '0' && letters[i] <= '9')
           {continue;}
        else if ((letters[i] == ' ')||(letters[i] =='\n')||(letters[i] == '\t'))
           {continue;}
        else
            letters[i] = ' ';
    }

1 Ответ

1 голос
/ 13 марта 2020

Просто угадай, но символьный метод IsLetterOrDigit определен для работы во всем диапазоне Юникода. Для документа page он включает все «Допустимые буквы и десятичные цифры, которые являются членами следующих категорий в UnicodeCategory: UppercaseLetter, LowercaseLetter, TitlecaseLetter, ModifierLetter, OtherLetter или DecimalDigitNumber."

I подумайте, что этот метод хранит символы (в частности, ModifierLetter и / или OtherLetter), которые вам не нужны и которые не включены в ваш шрифт, поэтому вы не можете их видеть.

Редактировать 1 : I проверил ваш алгоритм. Оказывается, пустая строка обходит ваши тесты, потому что она пропускает для l oop. Вам необходимо добавить длину строки сразу после того, как вы прочитаете строку из строки файла, это:

if (nextLine.length() == 0) {continue;}

Редактировать 2 : Кроме того, поскольку вы сканируете каждый символ, чтобы отсеять " без слов и без цифр ", вы также можете включить логи c, чтобы создать слова и добавить их в коллекцию. Как это может быть:

private static void WordSplitTest(String line) {
    char[] letters = line.trim().toCharArray();

    boolean gotWord = false;

    String word = "";

    for (int i = 0; i < letters.length; i++) {
        if (!Character.isLetterOrDigit(letters[i])) {

            if(!gotWord) {continue;}

            gotWord = false;

            AddWord(word);
        }
        if (gotWord) {
            word += Character.toString(letters[i]);
        }
    }
}

private static void AddWord(String word) {
    if (!map.containsKey(word)) {
        map.put(word, 1);
    } else {
        int value = (int) map.get(word);
        map.put(word, ++value);
    }
}
...