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

问题描述

我有以下示例字符串:

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 正则表达式中使用 约束宽度 后视模式支持,并使用限制量词如 {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} - 双反斜杠出现零到一千次
  • ) - 正向后视结束
  • \| - 一个 | 字符。