Reputation: 1824
I have special file format where I need to replace dozens of strings and reformat its structure. As the simplest solution I have prepared my patterns file where all regex definitions/replacements are stored (~100 replacements). I'm using perl to find and replace patterns (perl -p patterns source.file
). Everything so far so good.
However, there is one case I'm unable to resolve using regex. I need to replace strings in part of the whole line, i.e. replace string in within a sub-string only.
Example: For simplicity, I need to replace all "A" to "X" only in the middle string (delimited by ;).
Input line:
ABCD ABCD; ABCD ABCD; ABCD ABCD
Expected output:
ABCD ABCD; XBCD XBCD; ABCD ABCD
^ ^
the only replaced characters
This correctly replaces all characters:
s/A/X/g;
But I need to replace commas in the middle field only. I tried:
s/(.*?;.*?)A/\1X/g;
s/(.*?;.*)A(.*?;)/\1X\2/g; # alternative to find the last A
But this replaces either the first A. I can have multiple patterns like this to repeat the search&replace procedure but this does not sound like a good solution as I don't know how many A's I will have in the sub-string.
I tried to play with lookbehind but unsuccessfully. Please note, I just need a regex definition I could use in my patterns file (i.e. no perl code). Alternatively, I'm able to use sed
or awk
to handle this case but I'm not too much familiar with it.
Thanks, community!
Regex101: https://regex101.com/r/Ic4ciA/1
Upvotes: 1
Views: 105
Reputation: 91385
A perl one liner:
echo 'ABCD ABCD; ABCD ABCD; ABCD ABCD' | perl -pe 's/(?:.+?;|\G).*?\KA(?=.*?;)/X/g'
ABCD ABCD; XBCD XBCD; ABCD ABCD
Explanation:
(?: # non capture group
.+? # 1 or more any character but newline, not greedy
; # semicolon
| # OR
\G # restart from last match position
) # end group
.*? # 0 or more any character but newline, not greedy
\K # forget all we have seen until this position
A # letter A
(?= # positive lookahead, make sure we have after:
.*? # 0 or more any character but newline, not greedy
; # a semicolon
) # end lookahead
Upvotes: 1
Reputation: 521194
I don't know of a clean way to do this in one go using a regex tool alone. But if you are open to a more iterative approach, it can fairly easily be handled in any scripting language. Here is a Python script which gets the job done:
inp = "ABCD ABCD; ABCD ABCD; ABCD ABCD"
parts = inp.split(';')
index = 1
while index < len(parts)-1:
parts[index] = parts[index].replace('A', 'X')
index += 1
output = ';'.join(parts)
print(output)
This prints:
ABCD ABCD; XBCD XBCD; ABCD ABCD
The approach is to split the input string on semicolon, generating a list of terms. Then, iterate from the second to second-to-last term, doing a replacement of the letter A
to X
. Finally, join together to produce the output you want.
Upvotes: 0