我想在一行中复制多个匹配,替换部分匹配,但保持匹配的运行(这似乎是棘手的部分)。
例如:
Regex:
(x(\d)(,)?)
Replacement:
X$2,O$2$3
Input:
x1,x2,Z3,x4,Z5,x6
Output: (repeated groups broken apart)
X1,O1,X2,O2,Z3,X4,O4,Z5,X6,O6
Desired output (repeated groups, "X1,X2" kept together):
X1,X2,O1,O2,Z3,X4,O4,Z5,X6,O6
演示:https://regex101.com/r/gH9tL9/1
正则表达式是否可以使用,还是需要使用别的东西?
更新:Wills答案是我的预期。我发现可能有多次正则表达式。
答案 0 :(得分:1)
您必须将重复模式捕获为一个匹配项,并立即写出整个重复模式的替换项。您当前的模式无法分辨您的第一和第二场比赛x1,
和x2,
是否相邻。
我要说不,一个纯正的正则表达式是不可能的。
这是因为关于捕获组和替换的两个重要事实。
重复捕获组将返回上次捕获:
正则表达式能够使用<PATTERN>{1,}
,<PATTERN>+
或<PATTERN>*
形式捕捉重复任意时间的模式。但是<PATTERN>
内的任何捕获组只会返回模式最后一次迭代的捕获。这会阻止您捕获任意重复的匹配所需的能力。
&#34;坚持&#34;,你可能会说,&#34;我只想捕捉重复一到两次的模式,我可以使用(x(\d)(,)?)(x(\d)(,)?)?
&#34;这会带来我们点2。
没有条件替换
使用上面的模式,我们可以获得重复匹配所需的输出,但不能没有修改单独匹配替换。 请参阅:https://regex101.com/r/gH9tL9/2如果无法根据捕获组的存在关闭替换部分,我们无法实现所需的输出。
但是&#34;不,你不能这样做&#34;对黑客来说是一个挑战,我希望我被一个真正的正则表达式忍者所展示。
通过一些代码确实可以实现这一目标。
这是一个快速而又脏的python hack,使用两个正则表达式http://pythonfiddle.com/wip-soln-for-so-q/
这使用了python&#39; re.sub()
,它可以将匹配传递给一个正则表达式,返回一个返回替换字符串的函数ordered_repl
。通过在ordered_repl
中使用原始正则表达式,我们可以通过缓存X
和O
的列表来提取我们想要的信息并获得正确的顺序。
import re
input_string="x1,x2,Z3,x4,Z5,x6"
re1 = re.compile("(?:x\d,?)+") # captures the general thing you want to match using a repeating non-capturing group
re2 = re.compile("(x(\d)(,)?)") # your actual matcher
def ordered_repl(m): # m is a matchobj
buf1 = []
buf2 = []
cap_iter = re.finditer(re2,m.group(0)) # returns an iterator of MatchObjects for all non-overlapping matches
for cap_group in cap_iter:
capture = cap_group.group(2) # capture the digit
buf1.append("X%s" % capture) # buffer X's of this submatch group
buf2.append("O%s" % capture) # buffer O's of this submatch group
return "%s,%s," % (",".join(buf1),",".join(buf2)) # concatenate the buffers and return
print re.sub(re1,ordered_repl,input_string).rstrip(',') # searches string for matches to re1 and passes them to the ordered_repl function
答案 1 :(得分:1)
在我的具体案例中,我使用的是PowerShell,因此我能够提出以下内容:
(为了便于阅读而添加了换行符)
("x1,x2,z3,x4,z5,x6"
-split '((?<=x\d),(?!x)|(?<!x\d),(?=x))'
| Foreach-Object {
if ($_ -match 'x') {
$_ + ',' + ($_ -replace 'x','y')
} else {$_}
}
) -join ''
Outputs:
x1,x2,y1,y2,z3,x4,y4,z5,x6,y6
其中:
-split '((?<=x\d),(?!x)|(?<!x\d),(?=x))'
将字符串拆分为以下组:
x1,x2
,
z3
,
x4
,
z5
,
x6
使用正面和负面的前瞻和外观:
逗号与 x\d
之前和没有 x
之后:
(?<=x\d),(?!x)
逗号之前没有 x\d
,之后 x
:
(?<!x\d),(?=x)