Groovy 正则表达式:字符串拆分模式未返回与匹配器模式相同的结果

Groovy Regex: String Split pattern not returning same result as Matcher pattern

我正在尝试提取字符串中开始标记和结束标记之间的数据。有多个匹配项,我需要提取所有匹配项(无论是数组还是列表)

我有一个限制,无法在我的设置中使用 Regex 匹配器,因此我正在考虑将 string.split() 与正则表达式一起使用。

def str = "USELESS STUFF START:M A:STUFF1 B:MORE2 C:THAT3 END:M START:M A:STUFF4 B:MORE5 C:THAT6 END:M START:M A:STUFF7 B:MORE8 C:THAT9 END:M USELESS STUFF"

此模式与 Regex Matcher 一起使用,并提取开始标记和结束标记之间的所有匹配项。

def items = str =~ /(?s)(?<=START:M).*?(?=END:M)/

结果:

[ A:STUFF1 B:MORE2 C:THAT3, A:STUFF4 B:MORE5 C:THAT6, A:STUFF7 B:MORE8 C:THAT9 ]

但是,当我尝试在 string.split

上使用相同的模式时
def items = str.split(/(?s)(?<=START:M).*?(?=END:M)/)

它 returns 每场比赛的结束和开始标记本身,而不是它们之间的标记。

[USELESS STUFF START:M, END:M START:M, END:M START:M, END:M USELESS STUFF]

我错过了什么,为什么 Split 模式不返回与 Matcher 模式相同的组?

此行为与方法名称相对应:

  • 匹配 what text ?
  • 拆分 by what separator ?

Groovy 在这种情况下所做的基本上是在标准 Java API 上添加一些语法糖。该行 def items = str =~ /(?s)(?<=START:M).*?(?=END:M)/

相同
Matcher items = Pattern.compile("(?s)(?<=START:M).*?(?=END:M)").matcher(str);

此匹配器找到的组将是

 A:STUFF1 B:MORE2 C:THAT3 
 A:STUFF4 B:MORE5 C:THAT6 
 A:STUFF7 B:MORE8 C:THAT9

虽然 Matcher returns 匹配,但 Splitter 相反,将它们分开 - 它通过给定的正则表达式找到文本的部分并将它们视为分隔符,将它们切掉并返回剩下的部分:

START:M
//  A:STUFF1 B:MORE2 C:THAT3 is cut out since it's a separator
END:M START:M
//  A:STUFF4 B:MORE5 C:THAT6 is a separator
END:M START:M
//  A:STUFF7 B:MORE8 C:THAT9 is a separator
END:M

要实际获取 STARTEND 标记之间的数据,str.split(" END:M START:M | START:M | END:M ") 就可以了。像 indexOflastIndexOfsubstring 这样的标准字符串方法可以非常有效地去除无用的东西,并通过简单地在第一个 [=23 之前删除所有内容来只获得需要的组=] 和最后一个 END:M:

str.substring(str.indexOf("START:M ") + 8, str.lastIndexOf(" END:M"))
   .split(" END:M START:M ")

// or more groovy
str[str.indexOf("START:M ") + 8 .. str.lastIndexOf(" END:M") - 1]
   .split(" END:M START:M ")

(8是START:M的长度)