当前位置: 首页 > 知识库问答 >
问题:

Java-8正则表达式负lookbehind with'\R`

景英杰
2023-03-14

在回答另一个问题时,我编写了一个正则表达式来匹配所有空格,最多包括一个换行符。我对换行符匹配器使用负查找来完成此操作:

((?<!\R)\s)*

后来我想了想,我说,哦,不,如果有一个\r\n?它肯定会抓取第一个断行字符,然后我会被下一个字符串前面的伪字符卡住,对吗?

所以我回去测试(大概是修复)它。然而,当我测试该模式时,它匹配了整个\r\n。它不仅匹配\r,还留下\n正如人们所期望的那样。

"\r\n".matches("((?<!\\R)\\s)*"); // true, expected false

但是,当我使用文档中提到的“等效”模式时,它返回false。那么,这是Java的一个bug,还是有一个与之匹配的正当理由?

共有2个答案

段干跃
2023-03-14
匿名用户

实现#1。文档错误

资料来源:https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

这里说:

换线匹配器

。。。相当于\u000D\u000A |[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

但是,当我们尝试使用“等效”模式时,它返回false:

String _R_ = "\\R";
System.out.println("\r\n".matches("((?<!"+_R_+")\\s)*")); // true

// using "equivalent" pattern
_R_ = "\\u000D\\u000A|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029]";
System.out.println("\r\n".matches("((?<!"+_R_+")\\s)*")); // false

// now make it atomic, as per sln's answer
_R_ = "(?>"+_R_+")";
System.out.println("\r\n".matches("((?<!"+_R_+")\\s)*")); // true

所以Javadoc应该说:

。。。相当于(?

根据Sherman在Oracle JDK-8176029上于2017年3月9日更新:

“api文档没有错误,实现错误(当”0x0d 0x0a next“时,无法回溯”0x0d next.match()”。match()“失败)”

认识#2。回头看不仅仅是向后看

尽管有这个名字,一个lookback不仅能够向后看,而且可以包括甚至跳过当前位置。

考虑以下示例(来自rexegg.com):

"_12_".replaceAll("(?<=_(?=\\d{2}_))\\d+", "##"); // _##_

“这很有意思,有几个原因。首先,我们在“向后看”中有一个“向前看”,即使我们应该向后看,这个“向前看”通过匹配两个数字和后面的下划线跳过当前位置。这很有技巧。”

这对于我们的示例来说意味着,即使我们的当前位置可能是,这也不会阻止后面的人识别出它的\R后面紧跟着\R,然后将两者作为一个原子组绑定在一起,从而拒绝将当前位置后面的部分识别为单独的匹配。

注意:为了简单起见,我使用了诸如“我们当前的位置是”之类的术语,但是这并不是内部发生的情况的精确表示。

辛承志
2023-03-14

构造\R是一个宏,它将子表达式包围成一个原子组(?

这就是为什么它不会把他们分开。

注意:如果Java在lookbehind中接受固定的替换,那么可以使用\R,但如果引擎不接受,则会引发异常。

 类似资料:
  • 问题内容: 在回答另一个问题时,我写了一个正则表达式来匹配所有空格,最多不超过一个换行符。我为换行匹配器使用了负向后看: 之后我想了一下,我说,哦,不,如果有?它肯定会抢到第一个换行符,然后在下一个字符串的前面我会被一个假的东西卡住,对吗? 所以我回去测试(大概修复)它。但是,当我测试模式时,它与整个匹配。它不匹配只是留下正如人们所预料。 然而,当我使用中提到的“等价物”模式文档的,它返回fals

  • 问题内容: 我有这种模式: 这对于正数很好用,但是我也需要它做负数,例如“ T-1T3T44”应该工作。或者也许使用空格而不是’T’,所以它应适用于这样的字符串:“-1 2 3 2 -1 6 2”。抱歉,我以前没有真正使用过正则表达式。有什么建议吗?谢谢。 问题答案: 您是否想过尝试: 您会注意到我也将(零个或多个)更改为(一个或多个),因为从技术上讲,这不是数字:-)

  • 问题内容: 我正在尝试输入之间的内容,我的模式没有做正确的事,请帮忙。 下面是sudocode: 要求的输出: 之一 二 三 问题答案: 先行使用并在循环中使用,而不是: 看到它在线上工作:ideone 但是最好在这里使用split: 看到它在线上工作:ideone

  • 主要内容:正则表达式支持字符正则表达式(Regular Expression)又称正规表示法、常规表示法,在代码中常简写为 regex、regexp 或 RE,它是计算机科学的一个概念。 正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作,是一种可以用于模式匹配和替换的规范。一个正则表达式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)组成的文字模式,它用以描述在查找文字主体时待匹配的

  • 问题内容: 我需要这件事的帮助。查看以下正则表达式: 我想查找这样的词:“自制”,“ aaaa-bbb”而不是“ aaa-bbb”,而 不是 “ aaa–aa–aaa”。基本上,我想要以下内容: 单词-连字符-单词。 它适用于所有内容,但该模式会通过:“ aaa–aaa–aaa”,但不应通过。哪种正则表达式适用于此模式? 问题答案: 可以从表达式中删除反斜杠: 下面的代码应该工作 请注意,您可以使

  • 问题内容: 用java 方法剥离输入的字符串(如MY-CORP \ My.Name)中的MY-CORP \部分的正则表达式是什么,这样我只能得到My.Name部分? 我试过了 但是我 在索引4 ^附近 遇到了 意外的内部错误。 * 问题答案: 您的问题是反斜杠在Java字符串和正则表达式中都有特殊含义。因此,您需要在Java源代码中使用四个斜杠,将两个斜杠传递给regex解析器以在regex中获得