如何捕获多个重复的组?


80

我需要捕获相同模式的多个组。假设我有以下字符串:

HELLO,THERE,WORLD

我写了一个下面的模式

^(?:([A-Z]+),?)+$

我想要做的是捕获每个单词,这样第1组是:“ HELLO”,第2组是“ THERE”,第3组是“ WORLD”。我的正则表达式实际上仅捕获了最后一个,即“世界”。

我在这里测试我的正则表达式,我想将它与Swift一起使用(也许Swift中有一种方法可以某种方式获取中间结果,以便我可以使用它们?)

更新:我不想使用split。我现在只需要如何捕获与模式匹配的所有组,而不仅仅是最后一个。


5
为什么不分开,
rock321987 '16

为什么不使用[A-Z]+[^,]+捕获结果
rock321987 '16

rock321987,我更新了输入字符串。我需要完全提取遵循上述模式的字符串。我需要使所有组都匹配模式,而不仅仅是最后一个。我想知道如何使用正则表达式。
phbelov '16

1
rock321987,还不清楚什么?我需要将字符串中的每个单词都作为一个匹配组,但是我的模式仅捕获最后一个(“ WORLD”)。
phbelov '16

1
使用此答案来查找所有匹配项
rock321987 '16

Answers:


60

模式中只有一组,您只能在该组中获得一个准确的结果。如果捕获组被模式重复(您+在周围的非捕获组上使用了量词),则只会存储与它匹配的最后一个值。

您必须使用语言的正则表达式实现函数来查找模式的所有匹配项,然后必须删除非捕获组的锚点和量词(并且也可以省略非捕获组本身)。

或者,展开您的正则表达式,并让该模式在要获取结果的每个组中包含一个捕获组:

^([A-Z]+),([A-Z]+),([A-Z]+)$

13
如何调整以适应不同数量的字符串?例如HELLO,WORLD和HELLO,THERE,MY,WORLD。我正在寻找仅一个表达式来处理两个示例,并且为更长的字符串数组提供了内置的灵活性
Chris

9
@Chris不能一概而论。答案表明,捕获组只能捕获一件事,并且无法创建动态数量的捕获组。
Barmar

6

我认为您需要这样的东西。

b="HELLO,THERE,WORLD"
re.findall('[\w]+',b)

在Python3中哪个会返回

['HELLO', 'THERE', 'WORLD']

3

仅在回答中提供第2段的其他示例。我不确定在一场比赛中获得三组比赛而不是使用一组比赛进行三场比赛有多关键。例如,很时髦:

def subject = "HELLO,THERE,WORLD"
def pat = "([A-Z]+)"
def m = (subject =~ pat)
m.eachWithIndex{ g,i ->
  println "Match #$i: ${g[1]}"
}

Match #0: HELLO
Match #1: THERE
Match #2: WORLD

2

阅读Byte Commander的答案后,我想介绍一下可能的改进:

n只要您n预先确定,就可以生成一个匹配任何一个单词的正则表达式。例如,如果我想匹配1到3个字,则regexp:

^([A-Z]+)(?:,([A-Z]+))?(?:,([A-Z]+))?$

将匹配下一个句子,并带有一个,两个或三个捕捉组。

HELLO,LITTLE,WORLD
HELLO,WORLD
HELLO

您可以在Regex101上看到有关此正则表达式的完整详细说明。

如我所说,使用您喜欢的语言为您想要的任何组生成此正则表达式都非常容易。由于我不是一个敏捷的人,所以下面是一个红宝石示例:

def make_regexp(group_regexp, count: 3, delimiter: ",")
  regexp_str = "^(#{group_regexp})"
  (count - 1).times.each do
    regexp_str += "(?:#{delimiter}(#{group_regexp}))?"
  end
  regexp_str += "$"
  return regexp_str
end

puts make_regexp("[A-Z]+")

话虽如此,我建议在这种情况下不要使用正则表达式,split根据您的需要,还有许多其他很棒的工具,从简单到一些标记化模式。恕我直言,正则表达式不是其中之一。例如在红宝石中,我会使用类似str.split(",")str.scan(/[A-Z]+/)


1

实际上,您有一个捕获组,可以匹配多次。没有多个捕获组。

javascript(js)解决方案:

let string = "HI,THERE,TOM";
let myRegexp = /([A-Z]+),?/g;       //modify as you like
let match = myRegexp.exec(string);  //js function, output described below
while(match!=null){                 //loops through matches
    console.log(match[1]);          //do whatever you want with each match
    match = myRegexp.exec(bob);     //find next match
}

输出:

HI
THERE
TOM

句法:

// matched text: match[0]
// match start: match.index
// capturing group n: match[n]

如您所见,这将适用于任意数量的匹配项。


0

我知道我的答案来晚了,但是今天却发生了,我用以下方法解决了:

^(([A-Z]+),)+([A-Z]+)$

因此,第一组(([A-Z]+),)+将匹配所有重复的模式,但最后一个([A-Z]+)将与最终模式匹配。无论字符串中有多少个重复的组,这都是动态的。


1
这不是解决问题的方法。问题不是关于匹配字符串,而是关于捕获所有组。此正则表达式仍仅捕获第一个重复组的最后一个匹配项(带逗号),以及最后一个重复组的匹配项(不带逗号)。
gdwarf
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.