1

This is a follow-up to a previous question I had asked. For that question, I received an excellent answer by @markp-fuso demonstrating the use of an array of search patters for sed to perform a particular substitution task.

In this question, I would like to perform the same find and replace task of replacing all forms of pow(var,2) with square(var) but I would like to do this by using a regex variable.

The sample input and output files are below:

InputFile.txt:

pow(alpha,2) + pow(beta,2)
(3*pow(betaR_red,2))
2/pow(gammaBlue,3))
-pow(epsilon_gamma,2)+5

OutputFile.txt:

square(alpha) + square(beta)
(3*square(betaR_red))
2/pow(gammaBlue,3))
-square(epsilon_gamma)+5

After looking at this answer and some more tinkering on https://regex101.com/r/80Hp5Z/1/, I was able to describe the text between pow( and ,2) using (?<=pow\().*?(?=,2\)).

Using Bash, I am trying to form a two command solution where:

  1. First command sets var to (?<=pow\().*?(?=,2\))
  2. Second command performs sed "s/pow(${var},2)/square(${var})/g" InputFile.txt > OutputFile.txt

It seems once I figure out how to set var successfully in Step 1, I can proceed with the command in Step 2. However, after reading this question and this question I tried the following two commands but they did not perform any substitutions:

bash$ var="(?<=pow\().*?(?=,2\))"
bash$ sed "s/pow(${var},2)/square(${var})/g" InputFile.txt > OutputFile.txt

I would really appreciate some help forming a 2-command Bash solution as described above that makes use of a regex variable and transforms InputFile.txt into OutputFile.txt.

5
  • 1
    Probably a much better solution overall is to write your program in such a way that you can switch between these functions without changing the code, either via a #define (which obviously requires you to recompile the program, but is very easy to manage from a Makefile or similar) or even by rewriting the program so you can switch at run-time (via a command-line option then, or perhaps an environment variable). Commented Oct 3, 2020 at 20:15
  • @tripleee: Thanks, this idea is very interesting and I didn't know you can do this. If possible, could you please give me some tips or references on how I can write such a #define statement that allows seamless switching between pow(var,2) and square(var)? Commented Oct 3, 2020 at 20:25
  • How to replace pow(foo(),2) would have been a far more interesting question since matching one ) is trivial but matching an unknown number of nested (...)s isn't. Commented Oct 3, 2020 at 21:02
  • 1
    Create a simple wrapper function which accepts one argument var, then returns either pow(var, 2) or square(var) depending on your #define. Post a new question if you can't figure it out (though I would guess it has been asked before; search before asking). Commented Oct 4, 2020 at 9:14
  • Ah, I see what you are trying to say. This is really cool and I can see myself using this in other situations as well. Thanks @tripleee. Commented Oct 4, 2020 at 19:13

2 Answers 2

2

If you want to deal with parentheses in squared expressions, try:

One-line Solution:

perl -pe 's/pow\s*\((([^()]|\((?2)+\))+)\s*,\s*2\s*\)/square($1)/g' inputFile.txt

Two-Line Solution:

REGEX="pow\s*\((([^()]|\((?2)+\))+)\s*,\s*2\s*\)"
perl -pe "s/$REGEX/square(\1)/g" inputFile.txt

https://regex101.com/r/Dp0Duf/1.

Sign up to request clarification or add additional context in comments.

5 Comments

Alexander Mashin, thanks a lot for the perl solution, it works perfectly. Would it be possible to make this into a two-command solution, where the first command sets var = a regex and then in the second command, this regex variable gets used in the perl command?
@procyon, create a file called, say, t: #!/bin/bash REGEX="pow\s*\((([^()]|\((?2)+\))+)\s*,\s*2\s*\)" perl -pe "s/$REGEX/square($1)/g" $1 Make it executable and call it like this: ./t file. P.S. The line breaks should be before REGEX and perl.
Thanks, I tried out your bash script using ./t file, but it converts pow(alpha,2) to square(file) instead of square(alpha). Could you please tell me why this happens when it looks equivalent to your one-liner after variable expansion?
Oh, sorry, it's funny. Two $1's are mixed up. Try this: #!/bin/bash REGEX="pow\s*\((([^()]|\((?2)+\))+)\s*,\s*2\s*\)" perl -pe "s/$REGEX/square(\1)/g" $1
Thanks so much, Alexander Mashin. I've accepted your answer and added your updated bash script as a two-line bash solution to your answer as a suggested edit. I sincerely appreciate your help.
1

You may use this sed with one capture group:

s='pow(\([^)]+),2\)'
sed -E "s/$s/square\1)/g" file
square(alpha) + square(beta)
(3*square(betaR_red))
2/pow(gammaBlue,3))
-square(epsilon_gamma)+5

RegEx Demo

5 Comments

Thanks, I tried this and it works! I'm trying to use (?<=pow\().*?(?=,2\)) (regex101.com/r/80Hp5Z/1). Would it be possible to use that in a sed substitution command to get the same result?
No, you cannot use lookahead and lookbehind in sed.
Thanks @anubhava. One of the things I am confused about in my question is how to first set the regex part of a sed command as a variable and then use it later on in the actual sed command. Would it be possible to add a two-liner solution to your answer where the first command sets var to a regex and in the second command var gets used by sed to perform the substitution?
Sorry I went to sleep after previous comment. I have updated my answer.
Your two step solution will work really well with a workflow involving 1) tinkering on regex101.com and setting a regex variable 2) applying the sed command. Thanks @anubhava, I appreciate your help!

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.