[英]Java-8 regex negative lookbehind with `\R`
在回答另一個問題時 ,我寫了一個正則表達式來匹配所有空格,最多包括一個換行符。 我使用負面的lookbehind為\\R
linebreak matcher做了這個:
((?<!\R)\s)*
后來我想着它,我說,哦,不,如果有\\r\\n
? 當然它會抓住第一個破線字符\\r
\\n
然后我會被我的下一個字符串前面的虛假\\n
卡住,對嗎?
所以我回去測試(並且可能修復)它。 但是,當我測試模式時,它匹配整個\\r\\n
。 它與人們可能期望的\\r
\\n
離開\\n
不匹配。
"\r\n".matches("((?<!\\R)\\s)*"); // true, expected false
但是,當我使用\\R
文檔中提到的“等效”模式時,它返回false。 這是Java的一個錯誤,還是它有匹配的正當理由?
構造\\R
是一個宏 ,它將子表達式包圍成一個原子組(?> parts )
。
這就是為什么它不會將它們分開。
注意:如果Java在lookbehind中接受固定的替換,使用\\R
是正常的,但如果引擎沒有,則會拋出異常。
實現#1。 文檔錯了
資料來源: https : //docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
這里說:
Linebreak matcher
......相當於
\ \ |[\ \\ \ \ \ \ ]
但是,當我們嘗試使用“等效”模式時,它返回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 doc沒錯,實現錯誤(當”0x0d + 0x0a + next.match()“失敗時,無法回溯”0x0d + next.match()“
實現#2。 Lookbehinds不僅向后看
盡管有這個名字,但是后視不僅能夠向后看,而且可以包括甚至跳過當前位置。
請考慮以下示例(來自rexegg.com ):
"_12_".replaceAll("(?<=_(?=\\d{2}_))\\d+", "##"); // _##_
“這很有趣有幾個原因。首先,我們在一個后視鏡中有一個前瞻,即使我們應該向后看,這個先行者通過匹配兩個數字和尾隨下划線跳過當前位置。這是雜技。”
這對於我們的\\R
的例子意味着什么,即使我們當前的位置可能是\\n
,這也不會阻止后視識別它的\\r
后跟\\n
,然后將兩者綁定在一起作為一個原子組,因此拒絕將當前位置背后的\\r
部分識別為單獨匹配。
注意:為簡單起見,我使用了諸如“我們當前位置是\\n
”之類的術語,但這並不是內部發生的精確表示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.