使用Regex的扫描仪无法读取整个文件

问题描述

这是我的解析方法

public void loadInput(File fileName) throws IOException {
    try {
      Scanner s = new Scanner(fileName);
      int numWords = 0;
      while (s.hasNext("(?<!')[\\w']+")) {
        System.out.println("word:" + s.next());
        numWords++;
      }
      System.out.println("Number of words: " + numWords);
    } catch (IOException e) {
      System.out.println("Error accessing input file!");
    }
  }

这是示例输入文件

Alice was beginning to get very tired of sitting by her sister
on the bank,and of having nothing to do:  once or twice she had
peeped into the book her sister was reading,but it had no
pictures or conversations in it,`and what is the use of a book,'
thought Alice `without pictures or conversation?'

  So she was considering in her own mind (as well as she Could,for the hot day made her feel very sleepy and stupid),whether
the pleasure of making a daisy-chain would be worth the trouble
of getting up and picking the daisies,when suddenly a White
Rabbit with pink eyes ran close by her.

它仅与以下单词匹配:

word:Alice
word:was
word:beginning
word:to
word:get
word:very
word:tired
word:of
word:sitting
word:by
word:her
word:sister
word:on
word:the
Number of words: 14

不知何故,扫描程序认为它已到达文件末尾,这不是事实。为什么会这样?我检查了我的Regex,它似乎确实有效(一个单词包含字母a-z和撇号)。谢谢!

解决方法

扫描程序将文本分为“令牌”。默认令牌分隔符为空格。当程序停止时,当前令牌为bank,。将其与.hasNext()正则表达式进行比较时,由于末尾有多余的逗号,因此它不匹配。

一种解决方案可能是使扫描程序对.hasNext()和.next()方法都使用空格令牌分隔符,并将正则表达式应用于println语句。

while(s.hasNext()) {
   Matcher m = wordPattern.matcher(s.next());
   if (m.find()) {
       System.out.println("word:" + m.group(0))
   }
}
,

扫描仪的hasNext几乎没有用。

扫描仪的工作方式如下:

  1. 只要相关(在任何next() / nextX()呼叫或任何hasNext呼叫,但没有nextLine()呼叫中),确保扫描程序知道下一个令牌如果还没有,请从提要中读取另一个令牌,方法是完全忽略要求的内容,而是扫描流的末尾或“定界符”(默认情况下为“任何空白”)。直到此为止的所有内容都是下一个标记。
  2. hasX()检查下一行的令牌,并根据其是否匹配返回true或false。与是否还有剩余数据要读取无关。
  3. nextLine会忽略所有这些内容,并且无法与扫描仪中的其他任何东西很好地工作。

因此,您正在调用hasNext,并且hasNext会忠实地报告:好吧,行中的下一个标记是bank,,并且与正则表达式不匹配,因此返回false。正如文档所说。

解决方案

忘记hasX,您不想要那些。您也永远不需要nextLine。如果您在定界符不好的情况下更改定界符(即,永远不要调用nextLine,而是调用useDelimiter("\r?\n")next()并调用.nextX()方法,则扫描程序的工作效果最佳。这就是您要做的所有事情。

因此,只需调用next(),检查其是否匹配,然后继续即可。