3
$\begingroup$

I am trying to do the following:

Take a string abcdEFGpcf and replace whatever is between abcd and pcf by something that depends on EFG, for example by EFGH and then obtain abcdEFGHpcf. I am trying to use regex for this but I'm extremely confused by the notation.

I guess it's also possible to do this with string patterns but I am also confused by the notation. I know how to replace a fixed substring by something else, but in this case we need to reference $x=$ EFG and put it in the new expression.

$\endgroup$
2
  • $\begingroup$ Do you mean something like: StringReplace["abcdEFGpcf", "abcd" ~~ x__ ~~ "pcf" :> "abcd" ~~ ToLowerCase[x] ~~ "pcf"] ? $\endgroup$
    – Domen
    Commented May 12, 2023 at 19:27
  • $\begingroup$ @Domen Quite there. I was looking for StringReplace["abcdEFGpcf", "abcd" ~~ x__ ~~ "pcf" :> "abcd" ~~ x ~~ "H" ~~ "pcf"] but your code helped me a lot. And I guess now I solved this doubt and all further doubts I had. Thank you so much! $\endgroup$
    – Red Banana
    Commented May 12, 2023 at 19:29

2 Answers 2

6
$\begingroup$

Let's put your transformation into a function for re-usability:

func[str_] := str <> "H"

Here's your input:

input = "abcdEFGpcf"

Now, we can use either string expressions or RegularExpression:

StringReplace[input, head : "abcd" ~~ mid___ ~~ tail : "pcf" :> head <> func[mid] <> tail]

"abcdEFGHpcf"

In the above, I named the two constant patterns to avoid repeating them in the rule.

StringReplace[input, RegularExpression["(abcd)(.*)(pcf)"] -> "$1" <> func["$2"] <> "$3"]

"abcdEFGHpcf"

In this case, we don't need to explicitly name the patterns, because we can use $n on the right hand side to reference a captured substring.

$\endgroup$
4
$\begingroup$

You could also just use StringReplacePart, no need for patterns !

s = "abcdYYYYpcfabcdXXXXpcf"
a = "abcd"
b = "pcf"
rep = "EFGH"

In the above s is your string. a and b are the first and last terminal strings, and you want to replace everything in between them with rep. Right? Then

p1 = StringPosition[s, a]
p2 = StringPosition[s, b]
m = MapThread[{#1[[2]] + 1, #2[[1]] - 1} &, {p1, p2}]

Mathematica graphics

The above gives the positions within s with each starting and ending terminal strings are located. Now use

StringReplacePart[s, rep, m]

Mathematica graphics

ps. I see now you want replacement to happen only if string inside these terminal strings depends "EFG". The above code can be modified to do that, by adding a check inside the MapThread to only pick these positions if the inner string satisfies this conditions.

This version only does the replacement if the inner string contains "EFG"

repl[s_String,from_,to_,lookfor_]:=If[StringContainsQ[StringTake[s,{from,to}],lookfor],{from,to},Nothing];
replaceSubStrings[s_String,fromS_String,toS_String,replS_String,lookFor_String]:=Module[{p1,p2,m,result=s},
    p1=StringPosition[s,fromS];
    p2=StringPosition[s,toS];
    If[Length[p1]>0&&Length[p1]>0,
       m=MapThread[repl[s,#1[[2]]+1,#2[[1]]-1,lookFor]&,{p1,p2}];
       If[Length[m]>0,
          result = StringReplacePart[s,replS,m]
       ]
    ];
    
    result
]

Example use:

replaceSubStrings["abcdEFGpcfabcdXXXXpcf", "abcd", "pcf", "EFGH", "EFG"]

Mathematica graphics

replaceSubStrings["abcdEFGpcfabcdXXXXpcfnnnnnabcdEFGzzzzzzpcf","abcd","pcf","EFGH","EFG"]    

Mathematica graphics

 replaceSubStrings["abcdxxxpcf", "abcd", "pcf", "EFGH", "EFG"]

Mathematica graphics

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.