1

I have a file that defines many methods with headers of the form

void Method1(double arg1[M][N], double arg2[M][N], ...)
{
}

I would like to use a bash script to replace the arguments "double arg1[M][N]" and "double arg2[M][N]" with "const vector<vector<double>>& arg1" and "vector<vector<double>>& arg2", respectively, so that the function header reads as

void Method1(const vector<vector<double>>& arg1, const vector<vector<double>>& arg2, ...)
{
}

How can I implement this using awk or sed? So far I have tried calling sed twice on the file like this

sed -i "s/double/const vector\<vector\<double\>\>\&/g" file.cpp

followed by

sed -i "s/\[M\]\[N\]//g" file.cpp

but the first call to sed matches anything with the pattern "double" in it, including methods with only scalar arguments of type double, which must remain untouched.

1
  • 1
    Fazlin -- you had a good approach, just sed 's/double \(arg[0-9]\)\[M\]\[N\]/const vector<vector<double>>\& \1/g' Commented Dec 20, 2019 at 9:23

2 Answers 2

3

The short version (well not that short) using sed with basic-regular-expressions could look something like:

sed -i 's/double arg1\[M\]\[N\],[ ]double arg2\[M\]\[N\]/const vector<vector<double>>\& arg1, const vector<vector<double>>\& arg2/' yourfiles

Example Use/Output

$ echo "void Method1(double arg1[M][N], double arg2[M][N], ...)" | 
sed 's/double arg1\[M\]\[N\],[ ]double arg2\[M\]\[N\]/const vector<vector<double>>\& arg1, const vector<vector<double>>\& arg2/'
void Method1(const vector<vector<double>>& arg1, const vector<vector<double>>& arg2, ...)

You can add the additional guard of 0,/double arg1\[M\]\[N\],[ ]double arg2\[M\]\[N\]/ before the s/.../.../ to ensure only the 1st occurrence in the file is replaced if you need to limit to 1 replacement.

Edit to Add Capture Groups and Backreferences

Per your comment, if the array names need to be generalized, you can match and capture the name with \([^[]*\) and reinsert the name using a numbered backreference (\1 and \2), e.g.

sed 's/double \([^[]*\)\[M\]\[N\],[ ]double \([^[]*\)\[M\]\[N\]/const vector<vector<double>>\& \1, const vector<vector<double>>\& \2/'

Edit Per-Request for awk Solution

As mentioned in the comment, this problem does not really lend itself to an awk solution for two reasons (1) the function declaration isn't a delimited set of fields that are easily broken on a field-separator; and (2) awk does not provide for in-place replacement within a file. (some versions do, otherwise you have to use write to a new file and replace the old)

To use awk for this problem, you basically have to systematically apply the string-manipulation functions to substitute the needed substrings. Doable, just not what you would consider a normal first-choice approach. You can do it similar to:

# match line with "... arg1[M][N], double arg2[M][N]"
awk -F", " '/[^[]*\[M\]\[N\],[ ][^[]*\[M\]\[N\]/ {
    gsub(/double/,"const vector<vector<double>>&")  # sub double/<vector<vector<double>>&
    gsub(/\[M\]\[N\]/,"")                           # remove [M][N]
}1' files                                           # print record

The command above simply substitutes double for the reference to vector of vector of doubles syntax using gsub to operate on the entire record. Then uses gsub again to remove the "[M][N]" leaving the record in the form desired. There are many ways to do this is just the first second way that came to mind with awk.

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

8 Comments

Thank you very much for your response. Your solution works perfectly for the given method signature. However, the argument names "arg1" and "arg2" were used only as examples; there are several of these methods defined in the file with different argument names. Is there a more generic way of matching double blah[M][N]?
Yes, you can use double \([^[]*])\[M\]\[N\], as the match with the capture group \(...\) preserving the name for each, but then you will need to re-insert the backreference. I'll drop an edit.
OK, it works! I mean, your generic version with capture groups and back references: sed -i 's/double \([^[]*\)\[M\]\[N\]/const vector<vector<double>>\& \1/g' file.cpp This is highly appreciated as it will save me long hours of manually editing the functions across several files.
I will accept this as the answer but how can it also be implemented using awk?
@unbound37 question is, why would you like to implement this in awk ? - looks like a job for sed
|
2

You could try below sed:

sed 's/double \(arg[0-9]\)\(\[[MN]\]\[[MN]\]\)/const vector\<vector\<double\>\>\& \1/g' file.cpp

The above command searches for pattern arg[0-9] between double and [M][N] and places that between your required const vector pattern. This can work with any number of arguments.

I have not included -i option of sed so that you can verify before updating.

2 Comments

I'll vote for that one too. Good use of the global. Note, you don't' have to escape < or > in the replace field. (see comment under original question)
Only downside would be if a function contained only one array (or more than two arrays) as parameters, you may trigger some stray replacements.

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.