HELLO,THERE,WORLD
我已经写了下面的模式
^(?:([A-Z]+),?)+$
我想要的是捕获每一个单词,所以第一组是:"HELLO",第二组是:"THERE",第三组是:"WORLD"。但是我的正则表达式实际上只捕获到最后一个,也就是"WORLD"。
我正在测试我的正则表达式here,我想要在Swift中使用它(也许在Swift中有一种方法可以获取中间结果,这样我就可以使用它们?)
我不想使用
split
。我只需要知道如何捕获与模式匹配的所有组,而不仅仅是最后一个。在一个模式中,如果只有一个组,那么你只能得到一个精确的结果。如果模式重复使用了捕获组(在周围的非捕获组上使用了+
量化符号),那么只有最后匹配的值会被存储。
你必须使用你语言的正则表达式实现函数来查找所有匹配项,然后需要删除非捕获组的锚点和量化符号(如果需要,也可以省略非捕获组本身)。
或者,扩展你的正则表达式,并让模式包含每个想要在结果中获得的组的一个捕获组:
^([A-Z]+),([A-Z]+),([A-Z]+)$
([A-Z]+)
)作为字符串或正则表达式模式(根据语言而定),并连接N个(在这种情况下用逗号分隔),然后将其转换为正则表达式模式或仅在正则表达式中使用它(再次取决于语言)。通常这很简单。(我假设这个答案认为可以动态构建它。) - zdim关键区别在于重复一个捕获组而不是捕获一个重复的组。
正如您已经发现的那样,区别在于重复一个捕获组仅捕获最后一次迭代。捕获一个重复的组会捕获所有迭代。
在 PCRE (PHP) 中:
((?:\w+)+),?
Match 1, Group 1. 0-5 HELLO
Match 2, Group 1. 6-11 THERE
Match 3, Group 1. 12-20 BRUTALLY
Match 4, Group 1. 21-26 CRUEL
Match 5, Group 1. 27-32 WORLD
由于所有的捕获都在第一个组中,所以您只需要使用$1
进行替换。
我使用了以下通用形式的正则表达式:
((?:{{RE}})+)
请参考regex101网站上的示例。
(\w+),?
,它会给你相同的结果。关键在于使用了g
标志,该标志重复匹配模式以匹配多个组。 - Thomas LAURENT((?:\w,?)+)
。
你在这里有多个匹配,只是因为有g标志,正如@thomas-laurent所说。
没有办法从一个捕获组中获得多个匹配。你必须提取并preg_match_all(或等效函数)重复组。 - PierreHELLO
…第3组是WORLD
…”您的区分很重要,因为此案例需要唯一的反向引用组。上面的表格显示了所有分配给“组1”的匹配项。因此,“((?:\w+)+),?”无法工作。接着,他说:“我需要捕获与模式匹配的所有组,而不仅仅是最后一个。”启用“g”标志的((?:\w+)+),?
可以实现这一点。 - ssent1((?:\w+)+),?
等价于(\w+),?
。你的匿名分组是不会重复出现的。这是误导性的,没有像“捕获多个匹配中的重复组”这样的东西。不幸的是,在正则表达式中没有任何东西可以多次匹配同一组。只有g标志和preg_match_all可以在剩余未匹配的字符串上迭代执行正则表达式。 - Pierreb = "HELLO,THERE,WORLD"
re.findall('[\w]+',b)
['HELLO', 'THERE', 'WORLD']
re.findall('\w+',b)
可以缩短2个字符。 因为只有一个表达式,所以不需要字符类。 - Jean-François Fabren
个单词(在n
预先确定的情况下)。例如,如果我想匹配1到3个单词,则正则表达式为:^([A-Z]+)(?:,([A-Z]+))?(?:,([A-Z]+))?$
将匹配下一句话,其中包含一个、两个或三个捕获组。
HELLO,LITTLE,WORLD
HELLO,WORLD
HELLO
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
到根据您的需求制定的一些令牌化模式。在我看来,正则表达式不是其中之一。例如,在Ruby中,我会使用类似于str.split(",")
或str.scan(/[A-Z]+/)
的东西。
([A-Z]+)((?:,([A-Z]+))?)+
?我刚刚检查过了,对于n个捕获组来说非常完美。 - pythonian29033[^,]+
并进行全局匹配(捕获),以获取字符串中的所有匹配结果。
如果您的模式需要更严格的限制,则可以调整排除列表。例如,要捕获由列出的任何标点符号分隔的单词
[^,.!-]+
这段代码从 hi,there-again!
中提取了所有单词,但没有包含标点符号。(除非 -
在一个范围内使用,如 a-z
或 0-9
,否则应该在字符类的最前面或最后面给出。)
在Python中:
import re
string = "HELLO,THERE,WORLD"
pattern = r"([^,]+)"
matches = re.findall(pattern,string)
print(matches)
use warnings;
use strict;
use feature 'say';
my $string = 'HELLO,THERE,WORLD';
my @matches = $string =~ /([^,]+)/g;
say "@matches";
在这个特定的例子中,实际上并不需要捕获()
,因为我们收集所有匹配的内容。但它们不会有任何影响,在一般情况下是必需的。
上面的方法对于其他模式也同样适用,包括在问题中尝试的那种模式(只要删除使其过于具体的锚定)。最常见的模式是捕获所有单词(通常意味着[a-zA-Z0-9_]
),模式为\w+
。或者,就像在问题中一样,只获取大写 ASCII 字母的子字符串[A-Z]+
。
仅提供第二段答案的额外示例。 我不确定对于您来说在一场比赛中获得三组而不是使用一组进行三场比赛有多重要。 例如,在Groovy中:
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
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(string); // find next match
}
语法:
// matched text: match[0]
// match start: match.index
// capturing group n: match[n]
正如您所看到的,这适用于任何数量的匹配。
^(([A-Z]+),)+([A-Z]+)$
(([A-Z]+),)+
将匹配所有重复的模式,除了最后一个([A-Z]+)
将匹配最后一个。而且这将是动态的,无论字符串中有多少个重复的组。示例代码是 JS 的,抱歉 :) 但是思路应该足够清晰了。
const string = 'HELLO,THERE,WORLD';
// First use following regex matches each of the list items separately:
const captureListElement = /^[^,]+|,\w+/g;
const matches = string.match(captureListElement);
// Some of the matches may include the separator, so we have to clean them:
const cleanMatches = matches.map(match => match.replace(',',''));
console.log(cleanMatches);
data="HELLO,THERE,WORLD"
pattern=r"([a-zA-Z]+)"
matches=re.findall(pattern,data)
print(matches)
输出
['HELLO', 'THERE', 'WORLD']
[A-Z]+
或[^,]+
来捕获结果? - rock321987