簡體   English   中英

Java String.split()正則表達式,用於處理轉義的分隔符和轉義轉義字符

[英]Java String.split() regex for handling escaped delimeter and escaped escape characters

String testString = "a\\,b\\\\,c,d\\\\\\,e,f\\\\g";
String[] splitedString = test.split(PATTERN_STRING);
for (String string : splitedString) {
    System.out.println(string);
}

這里我有一個String,它將List of String編碼為String,其中轉義字符是\\和分隔符,
注意:(由於Java代碼,示例中的反斜杠加倍)
反斜杠和逗號在原始字符串中轉義,結果字符串與逗號合並。 我需要一個正則表達式將此字符串拆分為原始的字符串列表。
以字符串為例

"a\,b\\,c,d\\\,e,f\\g"
我需要得到這樣的字符串:

 "a\\,b\\\\" "c" "d\\\\\\,e" "f\\\\g" 

因此split的邏輯很簡單:只有當前面的反斜杠數是偶數時才用分隔符逗號分隔:0,2,4 ......只有在這種情況下這個逗號是分隔符。 如果逗號之前的反斜杠數是奇數,則轉義為逗號並且不應發生拆分。

對於這種情況,任何人都能幫助我使用適當的正則表達式嗎?

編輯
我知道這個正則表達式: (?<!\\\\\\\\),將有助於用前面沒有反斜杠的逗號分隔字符串。 但在我的情況下,我需要拆分以防止逗號數為斜線之前的斜線。

感謝任何幫助。

如果它必須拆分,那么你可以嘗試類似的東西

split("(?<!(?<!\\\\)\\\\(\\\\{2}){0,1000000000}),")

我使用{0,1000000000}而不是*因為Java中的后視需要具有明顯的最大長度,並且1000000000似乎已經足夠好了,除非你的文本中有超過1000000000連續的\\\\


如果它不必split那么你可以使用

Matcher m = Pattern.compile("(\\G.*?(?<!\\\\)(\\\\{2})*)(,|(?<!\\G)$)",
        Pattern.DOTALL).matcher(testString);
while (m.find()) {
    System.out.println(m.group(1));
}

\\\\G表示上一次匹配的結束,或者如果這是Matcher的第一次迭代,並且字符串^沒有先前的匹配開始。


但是實現起來最快且不那么熱衷的是編寫自己的解析器,它將使用像escaped這樣的標志來表示當前檢查的字符是用\\轉義的。

public static List<String> parse(String text) {
    List<String> tokens = new ArrayList<>();
    boolean escaped = false;
    StringBuilder sb = new StringBuilder();

    for (char ch : text.toCharArray()) {
        if (ch == ',' && !escaped) {
            tokens.add(sb.toString());
            sb.delete(0, sb.length());
        } else {
            if (ch == '\\')
                escaped = !escaped;
            else
                escaped = false;
            sb.append(ch);
        }
    }

    if (sb.length() > 0) {
        tokens.add(sb.toString());
        sb.delete(0, sb.length());
    }

    return tokens;
}

演示所有方法:

String testString = "a\\,b\\\\,c,d\\\\\\,e,f\\\\g";
String[] splitedString = testString
        .split("(?<!(?<!\\\\)\\\\(\\\\{2}){0,1000000000}),");
for (String string : splitedString) {
    System.out.println(string);
}

System.out.println("-----");
Matcher m = Pattern.compile("(\\G.*?(?<!\\\\)(\\\\{2})*)(,|(?<!\\G)$)",
        Pattern.DOTALL).matcher(testString);
while (m.find()) {
    System.out.println(m.group(1));
}

System.out.println("-----");
for (String s : parse(testString))
    System.out.println(s);

輸出:

a\,b\\
c
d\\\,e
f\\g
-----
a\,b\\
c
d\\\,e
f\\g
-----
a\,b\\
c
d\\\,e
f\\g

嘗試,

我只是通過使用字符串操作來實現您的邏輯。

String string = "a\\,b\\\\,c,d\\\\\\,e,f\\\\g";
String finalString = "";
for(String i : string.split(",")){
    int count = 0;
    for(int j=0;j<i.length();j++)
        if(i.charAt(j) == '\\')
            count++;    
    finalString+=(count%2==0)?","+i+"$":","+i;
} 
for(String finalAns: finalString.split("\\$")){
    System.out.println(finalAns.replaceFirst(",", ""));
}

輸出:

a\,b\\
c
d\\\,e
f\\g

這將為您解決問題:

String[] splitedString = testString.split("(?<=[a-z])(\\\\{2})*,");

在這里,它是使用偶數(0是偶數這里)的\\從字符串后面是,對於拆分分隔符。

使用lookbehind ,它檢查\\之前的最后一個字符是否是字母表。

暫無
暫無

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

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