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
要实际获取 START
和 END
标记之间的数据,str.split(" END:M START:M | START:M | END:M ")
就可以了。像 indexOf
、lastIndexOf
和 substring
这样的标准字符串方法可以非常有效地去除无用的东西,并通过简单地在第一个 [=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
的长度)
我正在尝试提取字符串中开始标记和结束标记之间的数据。有多个匹配项,我需要提取所有匹配项(无论是数组还是列表)
我有一个限制,无法在我的设置中使用 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
要实际获取 START
和 END
标记之间的数据,str.split(" END:M START:M | START:M | END:M ")
就可以了。像 indexOf
、lastIndexOf
和 substring
这样的标准字符串方法可以非常有效地去除无用的东西,并通过简单地在第一个 [=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
的长度)