【问题标题】:regex to duplicate repeated patterns, substituting part of the pattern正则表达式复制重复的模式,替换部分模式
【发布时间】:2016-05-20 16:07:17
【问题描述】:

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

例如:

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

这可以使用正则表达式还是我需要使用其他东西?


更新:遗嘱的答案是我所期望的。我突然想到,多次传递正则表达式可能是可能的。

【问题讨论】:

    标签: regex


    【解决方案1】:

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

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

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

    1. 重复捕获组将返回最后一次捕获

      正则表达式能够通过使用<PATTERN>{1,}<PATTERN>+<PATTERN>* 形式来捕获重复任意时间量的模式。但是,<PATTERN> 中的任何捕获组都只会返回模式最后一次迭代的捕获。这将阻止您捕获任意重复的匹配项。

    “等等”,你可能会说,“我只想捕获重复一两次的模式,我可以使用(x(\d)(,)?)(x(\d)(,)?)?”,这将我们带到第 2 点。

    1. 没有条件替换

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


    但是“不,你不能那样做”对黑客来说是一个挑战,我希望我是一个真正的正则表达式忍者。


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

    肯定有办法通过一些代码来实现这个目标。

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

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

    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
    

    【讨论】:

    • 使用多个正则表达式怎么样?
    • 我实际上正在研究一点 python 可以通过两个正则表达式实现这一点
    • 有一个解决方案使用 2 个正则表达式和一些 python 列表来缓冲
    【解决方案2】:

    在我的具体情况下,我使用的是 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 '((?&lt;=x\d),(?!x)|(?&lt;!x\d),(?=x))'

    将字符串分成这些组:

    x1,x2
    ,    
    z3   
    ,    
    x4   
    ,    
    z5   
    ,    
    x6
    

    使用正负前瞻和后瞻:

    逗号withx\d之前和x之后:
    (?&lt;=x\d),(?!x)

    逗号不带 x\d之前和 x之后:
    (?&lt;!x\d),(?=x)

    【讨论】:

    • 很好地使用管道和子壳
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2021-07-17
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多