我正在用Java手工开发语法分析器,我想使用正则表达式解析各种令牌类型。问题是,如果输入不符合语法,我还希望能够准确报告当前行号。
长话短说,当我尝试将换行符与Scanner类匹配时,我遇到了一个问题。具体来说,当我尝试使用Scanner类将换行符与模式匹配时,它会失败。几乎总是。但是当我使用匹配器和相同的源字符串执行相同的匹配时,它会完全按照您的预期检索换行符。这是否有原因,我似乎无法发现,或者这是一个错误,我怀疑?
仅供参考:我无法在Sun数据库中找到描述此问题的错误,因此如果是错误,则尚未报告。
示例代码:
Pattern newLinePattern = Pattern.compile("(\\r\\n?|\\n)", Pattern.MULTILINE);
String sourceString = "\r\n\n\r\r\n\n";
Scanner scan = new Scanner(sourceString);
scan.useDelimiter("");
int count = 0;
while (scan.hasNext(newLinePattern)) {
scan.next(newLinePattern);
count++;
}
System.out.println("found "+count+" newlines"); // finds 7 newlines
Matcher match = newLinePattern.matcher(sourceString);
count = 0;
while (match.find()) {
count++;
}
System.out.println("found "+count+" newlines"); // finds 5 newlines
答案 0 :(得分:6)
您的useDelimiter()
和next()
组合有问题。 useDelimiter("")
将返回next()
上的1长子字符串,因为空字符串实际上位于每两个字符之间。
也就是说,因为"\r\n".equals("\r" + "" + "\n")
所以"\r\n"
实际上是两个令牌,"\r"
和"\n"
,由""
分隔。
要获得Matcher
- 行为,您需要findWithinHorizon
,这会忽略分隔符。
Pattern newLinePattern = Pattern.compile("(\\r\\n?|\\n)", Pattern.MULTILINE);
String sourceString = "\r\n\n\r\r\n\n";
Scanner scan = new Scanner(sourceString);
int count = 0;
while (scan.findWithinHorizon(newLinePattern, 0) != null) {
count++;
}
System.out.println("found "+count+" newlines"); // finds 5 newlines
findWithinHorizon(Pattern pattern, int horizon)
尝试查找指定模式的下一次出现[...]忽略分隔符[...]如果未检测到此类模式,则返回
null
[...]如果{{1} }是0,然后[...]此方法继续搜索输入,查找指定的模式而不受限制。
horizon
将标记为1-length子字符串答案 1 :(得分:3)
\r
,\n
,\n
,\r
,\r
,{{ 1}}和\n
。然后,当您调用hasNext时,它会检查下一个令牌是否与您的模式匹配(由于\n
上的?
,这些令牌都非常简单。因此while循环遍历7个标记中的每一个。
另一方面,匹配器会贪婪地匹配正则表达式 - 因此它会按预期将\r\n?
捆绑在一起。
强调扫描程序行为的一种方法是将正则表达式更改为\r\n
。这导致计数为0.这是因为扫描程序将第一个标记读取为(\\r\\n|\\n)
(不 \r
),然后通知它与您的模式不匹配,所以当你致电\r\n
时会返回false。
(简短版本:在使用您的令牌模式之前,扫描程序使用您的分隔符进行标记,匹配器不会进行任何形式的标记)
答案 2 :(得分:2)
值得一提的是,你的例子含糊不清。它可能是:
\r
\n
\n
\r
\r
\n
\n
(七行)
或:
\r\n
\n
\r
\r\n
\n
(五行)
?你使用过的量词是一个贪婪的量词,它可能会得到五个正确的答案,但是因为Scanner迭代了令牌(在你的情况下,由于你选择的分界模式,个别字符),它会不情愿地匹配,一次一个字符到达七个错误的答案。
答案 3 :(得分:0)
当您使用Scanner
分隔符""
时,它将生成每个字符长的标记。这是在应用新行正则表达式之前。然后它将这些字符中的每一个与新行正则表达式相匹配;每一个匹配,所以它产生7个令牌。但是,因为它将字符串拆分为1个字符的标记,所以它不会将相邻的\r\n
个字符组合成一个标记。