簡體   English   中英

使用`\\ R`進行Java-8正則表達式負向觀察

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM