如何在非转义分隔符上正确拆分?

How to properly split on a non escaped delimiter?

我有以下示例字符串:

A|B\|C\|D\\|E\\F

与 |是定界符,\ 是转义符。 正确的分割应该如下所示:

A
B\|C\
D\\|E\\
F

此外,如果分隔符或转义符由多个字符组成,我还需要此逻辑普遍适用。

我已经有一个在正确位置拆分的正则表达式,但它没有产生所需的输出:

正则表达式:

(?<!\Q\E)(?:(\Q\\E)*)\Q|\E

输出:

A
B\|C
D\\|E
F

我通常在这里测试:https://regex101.com/,但我在 java 工作,所以我有更多的能力。

还尝试了以下方法,但也没有得到肯定的结果(在网页上不起作用,但在 java 中并没有产生预期的结果):

(?=(\Q\\E){0,5})(?<!\Q\E)\Q|\E

提取方法

您可以使用匹配方法,因为它最稳定并且允许任意数量的转义 \ 字符。您可以使用

(?s)(?:\.|[^\|])+

regex demo详情:

  • (?s) - Pattern.DOTALL 嵌入标志选项
  • (?:\.|[^\|])+ - \ 的一次或多次重复,然后是任何一个字符,或除 \|.
  • 之外的任何字符

参见 Java demo:

String s = "A|B\|C\\|D\\\|E\\\\|F";
Pattern pattern = Pattern.compile("(?:\\.|[^\\|])+", Pattern.DOTALL);
Matcher matcher = pattern.matcher(s);
List<String> results = new ArrayList<>();
while (matcher.find()){
    results.add(matcher.group());
} 
System.out.println(results); 
// => [A, B\|C\, D\\|E\\, F]

拆分方法(split 的解决方法)

您可以(ab)在 Java 正则表达式中使用 constrained-width 后视模式支持,并使用限制量词 {0,1000} 而不是 * 量词。解决方法看起来像

String s = "A|B\|C\\|D\\\|E\\\\|F";
String[] results = s.split("(?<=(?<!\\)(?:\\{2}){0,1000})\|"); System.out.println(Arrays.toString(results));

参见 this Java demo

注意 (?:\{2}){0,1000} 部分最多只允许 1000 个转义反斜杠,我相信在大多数情况下应该足够了,但您可能想先测试一下。我仍然推荐第一个解决方案。

详情:

  • (?<= - 正面回顾的开始:
    • (?<!\) - 没有紧跟 \
    • 的位置
    • (?:\{2}){0,1000} - 双反斜杠出现零到一千次
  • ) - 正回顾结束
  • \| - 一个 | 字符。