正则表达式复制重复的模式,替换部分模式

时间:2016-05-20 16:07:18

标签: regex

我想在一行中复制多个匹配,替换部分匹配,但保持匹配的运行(这似乎是棘手的部分)。

例如:

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答案是我的预期。我发现可能有多次正则表达式。

2 个答案:

答案 0 :(得分:1)

您必须将重复模式捕获为一个匹配项,并立即写出整个重复模式的替换项。您当前的模式无法分辨您的第一和第二场比赛x1,x2,是否相邻。

我要说不,一个纯正的正则表达式是不可能的。

这是因为关于捕获组和替换的两个重要事实。

  1. 重复捕获组将返回上次捕获

    正则表达式能够使用<PATTERN>{1,}<PATTERN>+<PATTERN>*形式捕捉重复任意时间的模式。但是<PATTERN>内的任何捕获组只会返回模式最后一次迭代的捕获。这会阻止您捕获任意重复的匹配所需的能力。

  2. &#34;坚持&#34;,你可能会说,&#34;我只想捕捉重复一到两次的模式,我可以使用(x(\d)(,)?)(x(\d)(,)?)?&#34;这会带来我们点2。

    1. 没有条件替换

      使用上面的模式,我们可以获得重复匹配所需的输出,但不能没有修改单独匹配替换。 请参阅:https://regex101.com/r/gH9tL9/2如果无法根据捕获组的存在关闭替换部分,我们无法实现所需的输出。

    2. 但是&#34;不,你不能这样做&#34;对黑客来说是一个挑战,我希望我被一个真正的正则表达式忍者所展示。

      具有2个正则表达式和一些代码的解决方案

      通过一些代码确实可以实现这一目标。

      这是一个快速而又脏的python hack,使用两个正则表达式http://pythonfiddle.com/wip-soln-for-so-q/

      这使用了python&#39; re.sub(),它可以将匹配传递给一个正则表达式,返回一个返回替换字符串的函数ordered_repl。通过在ordered_repl中使用原始正则表达式,我们可以通过缓存XO的列表来提取我们想要的信息并获得正确的顺序。

      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)