首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用regex进行Java Scanner换行符解析(Bug?)

使用regex进行Java Scanner换行符解析(Bug?)
EN

Stack Overflow用户
提问于 2010-05-20 08:51:47
回答 4查看 5.1K关注 0票数 4

我正在用Java手工开发一个语法分析器,我想使用正则表达式来解析各种标记类型。问题是,如果输入不符合语法,我也希望能够准确地报告当前的行号。

长话短说,当我尝试将换行符与Scanner类实际匹配时,我遇到了一个问题。具体地说,当我尝试使用Scanner类将换行符与模式进行匹配时,它失败了。几乎总是如此。但是,当我使用Matcher和相同的源字符串执行相同的匹配时,它检索到的换行符也完全符合您的预期。有没有这样的原因,我似乎没有发现,或者这是一个bug,正如我怀疑的那样?

仅供参考:我在Sun数据库中找不到描述此问题的bug,因此如果是bug,则尚未报告。

示例代码:

代码语言:javascript
复制
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
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-05-20 09:28:47

您的useDelimiter()next()组合有问题。useDelimiter("")将在next()上返回一个长度为1的子字符串,因为实际上每两个字符之间就有一个空字符串。

也就是说,因为"\r\n".equals("\r" + "" + "\n")所以"\r\n"实际上是两个标记,"\r""\n",由""分隔。

要获取Matcher-behavior,您需要findWithinHorizon,它会忽略分隔符。

代码语言:javascript
复制
    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

API链接

  • findWithinHorizon(Pattern pattern, int horizon)尝试查找指定模式的下一个匹配项...忽略分隔符...如果没有检测到这样的模式,则返回null ...如果horizon为0,则...此方法继续搜索输入,查找未绑定的指定模式。

相关问题

票数 6
EN

Stack Overflow用户

发布于 2010-05-20 09:11:40

事实上,这是两者的预期行为。扫描器主要关心使用分隔符将事物拆分成令牌。因此,它(懒惰地)获取您的sourceString,并将其视为以下一组标记:\r\n\n\r\r\n\n。然后,当您调用hasNext时,它会检查下一个令牌是否与您的模式匹配(多亏了\r\n?上的?,它们都很容易做到这一点)。因此,while循环会遍历这7个标记中的每一个。

另一方面,匹配器将贪婪地匹配正则表达式-因此,它会将\r\n捆绑在一起。

强调扫描器行为的一种方法是将您的正则表达式更改为(\\r\\n|\\n)。这将导致计数为0。这是因为扫描程序将第一个令牌读取为\r (而不是\r\n),然后注意到它与您的模式不匹配,因此当您调用hasNext时返回false。

(简而言之:在使用令牌模式之前,扫描器使用分隔符进行标记,匹配器不做任何形式的标记)

票数 3
EN

Stack Overflow用户

发布于 2010-05-20 09:09:51

值得一提的是,您的示例是模棱两可的。可能是:

代码语言:javascript
复制
\r
\n
\n
\r
\r
\n
\n

(七行)

或者:

代码语言:javascript
复制
\r\n
\n
\r
\r\n
\n

(五行)

那个?您使用的量词是一个贪婪的量词,这可能会使five成为正确的答案,但因为Scanner迭代标记(在您的例子中是单个字符,由于您选择的定界模式),它将不情愿地匹配,一次一个字符,得出不正确的答案7。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2870393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档