【问题标题】:reading txt file and recording it's pages - JAVA读取txt文件并记录它的页面 - JAVA
【发布时间】:2020-06-03 18:16:12
【问题描述】:

我是一名新手软件学生,这是我第一次来这里,如果我发错地方了,非常抱歉。我有一个任务,包括读取一个文本文件,其中包含很多行(其中 40 行构成一页),将其拆分为单词,并为每个单词记录所有出现的事件以及它发生的所有页面。

重点是我只能使用链表(我可以创建自己的方法)和数组。我花了很长时间,但我只能存储拆分的单词,即使如此,我也在努力记录单词的页面和频率的逻辑部分......我在哪里存储每个单词的页码?它应该在一个数组中吗?或者我应该创建一个“Word”类来存储出现次数和页码?如果是这样,我是否还应该创建一个“页面”类来管理它?老实说,我已经尝试过这两种方法,但似乎没有一种对我有用,最后代码变得缓慢、混乱,我只是感到困惑,哈哈

已经感谢大家的帮助!!!

编辑:这就是我对问题的阅读和拆分部分的看法。这次我决定将所有单词存储在linkedList 中。在这里,我更改为 3 行 = 1 页。我还在最后留下了几行文本。问题是我不知道在哪里以及如何跟踪每 3 行组的页码

public void loadBook(){  
    Path path1 = Paths.get("alice.txt");
    int countLines = 0;
    stopwords(); //another method to load the stopwords
    try (BufferedReader reader = Files.newBufferedReader(path1, Charset.defaultCharset())) {
        String line = null;
        while ((line = reader.readLine()) != null) {
            String[] split = line.split(" ");
            ++countLines;
            for (int i = 0; i < split.length; ++i){
                if (stopwords.notContains(split[i].toLowerCase())){
                    pages.add(split[i]);
                }
            }   
            if (countLines % 3 == 0) {
                countPages++;
                countLines = 0;
            }
        }
    } catch (IOException e) {
        System.err.format("Erro na leitura do arquivo: ", e);
    }
}

第一章 兔子洞

爱丽丝开始厌倦坐在她姐姐身边 银行,无事可做:一两次她偷看 她姐姐正在读的书,但里面没有图片或对话 它,“那本书有什么用,”爱丽丝想,“没有图片或 对话?'

所以她在自己的脑海中考虑(尽她所能,因为 炎热的一天让她感到很困很愚蠢),无论是快感 做一个菊花链是值得的 采摘雏菊,突然一只粉红色眼睛的大白兔跑了过来 在她身边。

没有什么比这更了不起的了;爱丽丝也不这么认为 听到兔子对自己说,‘哦,天哪!

【问题讨论】:

  • 为什么不与我们分享您的代码?
  • edit 您的问题并发布示例文件。为了保持简短,让每页只有 4 行长,并提供 3 页,即 12 行。然后发布您希望结果的样子,例如可能是单词列表,每个单词旁边是整个文本中出现的总数以及该单词所在的所有页面的列表。然后也许有人将能够回答您的问题。
  • 这正是我需要的,显示单词并在它旁边显示它出现的页面。我将很快编辑答案以添加我的简化代码。谢谢

标签: java data-structures array-algorithms


【解决方案1】:

首先我想到了一个类来封装您需要从文本中提取的数据。您需要单个单词,并且对于每个单词,您都需要计算该单词在整个文本中出现的次数以及该单词出现的页面列表。于是我写了如下WordRef类。

import java.util.LinkedList;
import java.util.Objects;

public class WordRef {
    /** Number of times 'word' occurs in the text. */
    private int occurrences;

    /** The actual word. */
    private String word;

    /** List of page numbers where 'word' appears. */
    private LinkedList<Integer> pages;

    /**
     * Creates and returns instance of this class.
     * 
     * @param word - the actual word.
     */
    public WordRef(String word) {
        Objects.requireNonNull(word, "null word");
        this.word = word;
        occurrences = 1;
        pages = new LinkedList<Integer>();
    }

    /** Increment the number of occurrences of 'word'. */
    public void addOccurrence() {
        occurrences++;
    }

    /**
     * Add 'page' to the list of pages containing 'word'.
     * 
     * @param page - number of page to add.
     */
    public void addPage(Integer page) {
        if (!pages.contains(page)) {
            pages.add(page);
        }
    }

    /**
     * @return Number of occurrences of 'word'.
     */
    public int getOccurrences() {
        return occurrences;
    }

    /**
     * @return The actual 'word'.
     */
    public String getWord() {
        return word;
    }

    /**
     * Two 'WordRef' instances are equal if they both contain the exact, same word.
     */
    public boolean equals(Object obj) {
        boolean equal = false;
        if (obj != null) {
            Class<?> objClass = obj.getClass();
            if (objClass.equals(getClass())) {
                WordRef other = (WordRef) obj;
                String otherWord = other.getWord();
                equal = word.equals(otherWord);
            }
        }
        return equal;
    }

    /**
     * Equal 'WordRef' instances should each return the same hash code.
     */
    public int hashCode() {
        return word.hashCode();
    }

    /**
     * Returns a string representation of this instance.
     */
    public String toString() {
        return String.format("%s {%d} %s", word, occurrences, pages);
    }
}

注意LinkedList 的元素必须是对象,因此使用Integer 而不是int,因为int 是一个原语。另请注意,我们需要确定两个 WordRef 实例是否包含相同的单词。因此类WordRef 包含方法equals() 并且根据类java.lang.Objectjavadoc,如果一个类覆盖了方法equals(),那么它也应该覆盖方法hashCode()

现在是读取文本并处理它的代码。在您的问题中,您将所有代码放在名为loadBook() 的方法中。但是,为了创建minimal, reproducible example,我编写了一个单独的类,并将文本读取和处理代码放入方法main() 以及一些辅助方法中。这是该类的代码。

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AliceTxt {
    private static final int PAGE = 3;
    private static final Pattern REGEX = Pattern.compile("\\b\\w+\\b");

    private static LinkedList<WordRef> wordRefs;

    private static List<String> getWords(String line) {
        if (line == null) {
            line = "";
        }
        Matcher matcher = REGEX.matcher(line);
        List<String> words = new ArrayList<>();
        while (matcher.find()) {
            words.add(matcher.group());
        }
        return words;
    }

    private static void updateWordRefs(List<String> words, int page) {
        if (words != null) {
            for (String word : words) {
                WordRef wordRef = new WordRef(word);
                int index = wordRefs.indexOf(wordRef);
                if (index < 0) {
                    wordRefs.add(wordRef);
                }
                else {
                    wordRef = wordRefs.get(index);
                    wordRef.addOccurrence();
                }
                wordRef.addPage(Integer.valueOf(page));
            }
        }
    }

    public static void main(String[] args) {
        Path path1 = Paths.get("alice.txt");
        try (BufferedReader reader = Files.newBufferedReader(path1, Charset.defaultCharset())) {
            wordRefs = new LinkedList<>();
            String line = reader.readLine();
            int countLines = 0;
            int page;
            while (line != null) {
                page = (countLines / PAGE) + 1;
                if (line.length() > 0) {
                    // Don't count empty lines.
                    countLines++;
                }
                List<String> words = getWords(line);
                updateWordRefs(words, page);
                line = reader.readLine();
            }
            wordRefs.forEach(System.out::println);
        }
        catch (IOException xIo) {
            xIo.printStackTrace();
        }
    }
}

上面的类使用另一个LinkedList 将文本中所有不同的单词保存为单独的WordRef 对象。请注意,在上面的代码中,单词是区分大小写的,这意味着 Soso 被视为单独的单词。如果您希望单词不区分大小写,即 Soso 应被视为同一个单词,请使用 java.util.regex.Pattern

类中的以下方法
private static final Pattern REGEX = Pattern.compile("\\b\\w+\\b", Pattern.CASE_INSENSITIVE);

以下是根据我的comment to your question 中的描述运行上述代码的输出,说明您希望输出如何显示以及您确认是正确的描述。
下面的每一行都以实际单词开头,然后是出现次数,然后是该单词在文本中出现的页码列表。参考类WordRef中的方法toString()

Alice {3} [1, 3]
was {4} [1, 2, 3]
beginning {1} [1]
to {4} [1, 3]
get {1} [1]
very {2} [1, 2]
tired {1} [1]
of {6} [1, 2, 3]
sitting {1} [1]
by {2} [1, 2]
her {5} [1, 2]
sister {2} [1]
on {1} [1]
the {9} [1, 2, 3]
bank {1} [1]
and {4} [1, 2]
having {1} [1]
nothing {2} [1, 3]
do {1} [1]
once {1} [1]
or {3} [1]
twice {1} [1]
she {3} [1, 2]
had {2} [1]
peeped {1} [1]
into {1} [1]
book {2} [1]
reading {1} [1]
but {1} [1]
it {3} [1, 3]
no {1} [1]
pictures {2} [1]
conversations {2} [1]
in {3} [1, 2, 3]
what {1} [1]
is {1} [1]
use {1} [1]
a {3} [1, 2]
thought {1} [1]
without {1} [1]
So {1} [2]
considering {1} [2]
own {1} [2]
mind {1} [2]
as {2} [2]
well {1} [2]
could {1} [2]
for {1} [2]
hot {1} [2]
day {1} [2]
made {1} [2]
feel {1} [2]
sleepy {1} [2]
stupid {1} [2]
whether {1} [2]
pleasure {1} [2]
making {1} [2]
daisy {1} [2]
chain {1} [2]
would {1} [2]
be {1} [2]
worth {1} [2]
trouble {1} [2]
getting {1} [2]
up {1} [2]
picking {1} [2]
daisies {1} [2]
when {1} [2]
suddenly {1} [2]
White {1} [2]
Rabbit {2} [2, 3]
with {1} [2]
pink {1} [2]
eyes {1} [2]
ran {1} [2]
close {1} [2]
There {1} [3]
so {2} [3]
VERY {2} [3]
remarkable {1} [3]
that {1} [3]
nor {1} [3]
did {1} [3]
think {1} [3]
much {1} [3]
out {1} [3]
way {1} [3]
hear {1} [3]
say {1} [3]
itself {1} [3]
Oh {1} [3]
dear {1} [3]

【讨论】:

  • 非常感谢您提供如此详细的解释。阅读您的代码,我可以说我不知道​​您使用的某些语法(例如 Matcher),但为每个单词创建一个类绝对是正确的方法。将深入研究您的代码,但再次感谢队友,真的很有帮助!!!
猜你喜欢
  • 1970-01-01
  • 2013-07-17
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2014-02-18
  • 2017-07-14
相关资源
最近更新 更多