关于regex:dart:使用正则表达式拆分字符串并包含定界符

dart: split string using regular expression and include delimiters

在Dart中,我想使用正则表达式拆分字符串并将匹配的定界符包括在结果列表中。因此,使用定界符.,我希望将字符串123.456.789拆分为[ 123, ., 456, ., 789 ]

根据https://stackoverflow.com/a/15668433,在某些语言中,例如C#,JavaScript,Python和Perl,可以通过在捕获括号中简单地包含分隔符来完成此操作。该行为似乎已记录在https://ecma-international.org/ecma-262/9.0/#sec-regexp.prototype-@@split。

但是,这似乎在Dart中不起作用:

print("123.456.789".split(new RegExp(r"(\\.)")));

产生与没有括号时完全相同的东西。有没有办法让split()在Dart中像这样工作?否则,我想它将必须是allMatches()实现。

编辑:将((?<=\\.)|(?=\\.))放在正则表达式中显然可以完成单个分隔符的工作,并具有后向和向前。我实际上会有很多定界符,并且我不确定这种方法的效率。有人可以建议吗?易读性当然降低了:要允许分隔符.;,将需要
((?<=\\.)|(?=\\.)|(?<=;)(?=;))
要么
((?<=\\.|;)|(?=\\.|;)
测试中

print("123.456.789;abc;.xyz.;ABC".split(new RegExp(r"((?<=\\.|;)|(?=\\.|;))")));

表示两者均有效。


标准库中没有对它的直接支持,但是基于RegExp.allMatches()滚动自己的实现非常简单。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
extension RegExpExtension on RegExp {
  List<String> allMatchesWithSep(String input, [int start = 0]) {
    var result = <String>[];
    for (var match in allMatches(input, start)) {
      result.add(input.substring(start, match.start));
      result.add(match[0]);
      start = match.end;
    }
    result.add(input.substring(start));
    return result;
  }
}

extension StringExtension on String {
  List<String> splitWithDelim(RegExp pattern) =>
      pattern.allMatchesWithSep(this);
}

void main() {
  print("123.456.789".splitWithDelim(RegExp(r"\\.")));
  print(RegExp(r"").allMatchesWithSep("lorem ipsum dolor sit amet"));
}


在单个定界符上分割

给定您的初始字符串:

1
123.456.789

和预期结果(分割符并包括定界符):

1
[123, ., 456, ., 789]

您可以提出以下正则表达式:

1
(?!^|$)\\b

匹配与单词边界匹配的位置,行的开头/结尾除外。

分割多个定界符

现在进行编辑,并给出以下字符串:

1
123.456.789;abc;.xyz.;ABC

您想要预期的结果(拆分并包含多个定界符):

1
[123, ., 456, ., 789, ;, abc, ;, ., xyz, ., ;, ABC]

您可以使用以下正则表达式(改编自第一个-添加的交替):

请参阅此处的正则表达式示例(出于显示目的,我通过使用换行符替换来模拟拆分)。

以下工作之一。

1
2
3
4
5
(?!^|$)\\b|(?!\\w)\\B(?!\\w)
(?!^|$)\\b|(?=\\W)\\B(?=\\W)

# the long way (with case-insensitive matching) - allows underscore _ as delimiter
(?!^|$)(?:(?<=[a-z\\d])(?![a-z\\d])|(?<![a-z\\d])(?=[a-z\\d])|(?<![a-z\\d])(?![a-z\\d]))

匹配与单词边界匹配的位置,除了行的开始/结束;或匹配的位置与字词边界不匹配,但以非字字符开头或之后。

注意:自添加了向后支持以来,此功能将在Dart 2.3.0及更高版本中有效(请参阅此处以获取更多信息)。