java 中的索引书

Indexing book in java

我正在尝试编写一个程序,将文本文件作为输入,在其中添加单词作为键,并且与单词相关联的值应该是它们所在的页码。文本如下所示:

Page1
blah bla bl
Page2
some blah

所以对于单词 "blah" 输出必须是

blah : [1,2].

我只插入了键,但不知道如何向它们插入关联值。这是我目前拥有的:

 BufferedReader reader = new BufferedReader(input);
    try {
    Map <String, List<Integer>> library 
            = new TreeMap<String, List<Integer>>();
        String line = reader.readLine(); 
        while (line != null) {
            String[] tokens = line.trim().split("\s+");
            for (int i = 0; i < tokens.length; i++) {
                String word = tokens[i];
                if (!library.containsKey(word) 
                         && !word.startsWith("Page")) {
                    library.put(word, new LinkedList<Integer>());
                    if (tokens[0].startsWith("Page")
                           && library.containsKey(word)) {
                        List<Integer> pages = library.get(word);
                        int page = getNum(tokens[0]);
                        pages.add(page);
                        page++;
                    }
                }
             }
         }
         line = reader.readLine();
      }
 }

要获取页数,我使用此方法

 private static int getNum(String s) {
    int result = 0;
    int p = 1;
    int i = s.length() - 1;
    while (i >= 0) {
        int d = s.charAt(i) - '0';
        if (d >= 0 && d <= 9) {
            result += d * p;
        } else {
            break;
        }
        i--;
        p *= 10;
    }
    return result;     
 }

感谢您的所有想法!

你应该尝试这样的事情。我不完全确定你是如何使用这些页面的,但这段代码将检查图书馆是否包含这个词(就像你已经拥有的那样),如果不包含,它会将页码添加到该词的列表中。

if (!library.containsKey(word) && !word.startsWith("Page")) {
    library.put(word, new LinkedList<Integer>());
}
else {
    library.put(word, library.get(word).add(page));
}

pages 变量在内部 if 语句的范围内声明。一旦该块结束,变量就超出范围并且未定义。如果您想稍后使用页面列表,则需要将其声明为 class 变量。

我假设您稍后使用 pages 生成 table 内容。但这并不是绝对必要的,因为您可以稍后从您的单词索引中生成它 - 我将在下面演示如何做到这一点。

您还需要声明一个 currentPage 变量来保存您看到的最新 'PageN' 文本。无需手动增加:您只需将数字存储在文本中(处理空白页)。

页码似乎总是在他们自己的行上,因此页面检测应该在行文本上而不是在单词上(这处理了一行读取 'for more information see Page72' 的情况)。

检查第一个词前是否有有效的页码也是值得的。

因此,将所有这些放在一起,您的代码的结构应该类似于以下内容:

Map<String, Set<Integer>> index = new TreeMap<>();
int currentPage = -1;
String currentLine;
while ((currentLine = reader.readLine()) != null) {
    if (isPage(currentLine)) {
        currentPage = getPageNum(currentLine);
    } else {
        assert currentPage > 0;
        for (String word: words(currentLine)) {
            if (!index.contains(word))
                index.put(word, new TreeSet<>());
            index.get(word).add(currentPage);
        }
    }
}

我已将方法 wordsisPagegetPageNum 分开,但您似乎拥有所有这些方法的工作代码。

我还将页面列表更改为集合,以反映您只需要在索引中引用一次单词页面这一事实。

要从索引中获取所有页面的有序列表,请使用:

index.values().stream()
    .flatMap(List::stream).distinct().sorted()
    .collect(Collectors.toList());

这是假设 Java8,但如果您没有流,转换起来并不难。

如果您要生成反向索引(页面到单词),那么出于效率原因,您应该在处理单词时创建反向映射 (Map<Integer, List<String>>)。

你的问题好像出在这段逻辑上:

                if (tokens[0].startsWith("Page")
                       && library.containsKey(word)) {

很明显,您仅在行以 Page 开头时才添加页码,否则 if 条件中的逻辑未执行,因此您从未更新任何单词的页码。