Search code examples
regexsublimetext3regex-group

replace groups in regex loop


I have these 2 lines:

What is P(output1|cause1=2, cause2=2)
What is P(output2|cause3=2)

I would like to change it to:

method_to_use(model, {"cause1": 2, "cause2": 2}, "output1")
method_to_use(model, {"cause3": 2}, "output2")

this is my regex:

.*P[(]([a-z1-9]+)[|](([a-z1-9]+)=([1-9]),?)+[)]

and I try to replace it like this:

method_to_use(model, {"$3": $4}, "$1")

but I only get the last fit of the group:

method_to_use(model, {"cause2": 2}, "output1")

is it possible to do some kind of a "loop" and change all fits on the way?


Solution

  • You could match the string with the following regular expression.

    ^.*P\(([^|]+)\|([^=]+)=(\d+)(?:, +([^=]+)=(\d+))?\)$
    

    If capture group 4 is non-empty replace the (whole-string) match with

    method_to_use(model, {"$2": $3, "$4": $5}, "$1")
    

    This causes the string

    What is P(output1|cause1=2, cause2=2)
    

    to be replaced with

    method_to_use(model, {"cause1": 2, "cause2": 2}, "output1") 
    

    Demo 1

    If capture group 4 is empty replace the match with

    method_to_use(model, {"$2": $3}, "$1")
    

    This causes the string

    What is P(output2|cause3=2)
    

    to be replaced with

    method_to_use(model, {"cause3": 2}, "output2")
    

    Demo 2

    Note that the regular expressions at the two links are equivalent, the only difference is that at Demo 1 I expressed the regex in free-spacing mode, which permits it to be self-documenting.

    Instead of replacing the entire string one could of course simply form the new string from the values of the capture groups. If that is done ^.*P at the beginning of the regex could be changed to simply P.

    The regex engine performs the following operations.

    ^             # match beginning of line
    .*P\(         # match 0+ chars then '|('      
    ([^|]+)       # save 1+ chars except '|' in cap grp 1 (output)    
    \|            # match ':'
    ([^=]+)       # save 1+ chars except '=' in cap grp 2 (causeA)
    =             # match '='
    (\d+)         # save 1+ digits in cap grp 3 (causeAval)
    (?:           # begin non-cap grp
      ,\ +        # match ',' then 1+ spaces
      ([^=]+)     # match 1+ chars except '=' in cap grp 4 (causeB)   
      =           # match '='
      (\d+)       # match 1+ digits in cap grp 5 (causeBval)
    )?            # end non-cap grp and make it optional  
    \)            # match ')'
    $             # match end of line