簡體   English   中英

Java替換所有正則表達式錯誤

[英]Java replaceAll regex error

我想將所有“*”轉換為“。*”,除了“\\ *”

String regex01 = "\\*toto".replaceAll("[^\\\\]\\*", ".*");
assertTrue("*toto".matches(regex01));// True

String regex02 = "toto*".replaceAll("[^\\\\]\\*", ".*");
assertTrue("tototo".matches(regex02));// True

String regex03 = "*toto".replaceAll("[^\\\\]\\*", ".*");
assertTrue("tototo".matches(regex03));// Error

如果“*”是第一個出現錯誤的字符:java.util.regex.PatternSyntaxException:在索引0附近懸掛元字符'*'

什么是正確的正則表達式?

這是目前唯一能夠連續處理多個轉義\\解決方案:

String regex = input.replaceAll("\\G((?:[^\\\\*]|\\\\[\\\\*])*)[*]", "$1.*");

這個怎么運作

讓我們打印字符串regex來查看正則表達式引擎正在解析的實際字符串:

\G((?:[^\\*]|\\[\\*])*)[*]

((?:[^\\\\*]|\\\\[\\\\*])*)匹配不是\\*的字符序列,或者轉義序列\\\\\\* 我們匹配我們不想觸摸的所有字符,並將其放入捕獲組中,以便我們可以將其放回原處。

上面的序列之后是未轉義的星號,如[*]

為了確保當正則表達式與未轉義的*不匹配時我們不“跳轉”, \\G用於確保下一個匹配只能從字符串的開頭或最后一個匹配的位置開始結束。

為什么這么長的解決方案? 有必要,因為后視構造檢查Java正則表達式是否正式支持連續\\前面的a *是奇數還是偶數。 因此,我們需要從左到右使用字符串,考慮轉義序列,直到我們遇到未轉義的*並用.*替換它。

測試程序

String inputs[] = {
    "toto*",
    "\\*toto",
    "\\\\*toto",
    "*toto",
    "\\\\\\\\*toto",
    "\\\\*\\\\\\*\\*\\\\\\\\*"};

for (String input: inputs) {
    String regex = input.replaceAll("\\G((?:[^\\\\*]|\\\\[\\\\*])*)[*]", "$1.*");
    System.out.println(input);
    System.out.println(Pattern.compile(regex));
    System.out.println();
}

樣本輸出

toto*
toto.*

\*toto
\*toto

\\*toto
\\.*toto

*toto
.*toto

\\\\*toto
\\\\.*toto

\\*\\\*\*\\\\*
\\.*\\\*\*\\\\.*

你需要在這里使用負面的lookbehind:

String regex01 = input.replaceFirst("(?<!\\\\)\\*", ".*");

(?<!\\\\\\\\)是一個負面的lookbehind,意味着匹配*如果它沒有反斜杠。

例子:

regex01 = "\\*toto".replaceAll("(?<!\\\\)\\*", ".*");
//=> \*toto

regex01 = "*toto".replaceAll("(?<!\\\\)\\*", ".*");
//=> .*toto

您必須在正則表達式中滿足以*開頭的字符串的大小寫:

(^|[^\\\\])\\*

單個插入符表示“字符串的開頭”(“開始錨點”)。

編輯

除了上面的更正之外, replaceAll調用中的替換字符串必須是$1.*而不是.*以免在未轉義的*丟失之前匹配的字符。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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