问题
- i need to replace all occurrences of a string within another string, if the original string matches some filter
- i can only use a single regex using an
scommand, because i need to send the assembled command to a 3rd party API
i have tried to use positive lookahead as to not consume the string in which i want to replace characters, but somehow i can not get the replacing to work as expected.
here is what i have tried so far and what was the outcome:
(note that the filter - here [0-9]+ is just an example and will be passed in from the call site and i can not directly influence it.
expected result: 9999997890
perl -e '$x = "4564567890"; $x =~ s/(?=^[0-9]+$)456/999/g; print $x'
actual result: 9994567890
- this replaces only the first occurrence of
456. why is this happening? - even less understandable for me is that if i change the filter lookahead to
(?=.*), both occurrences of 456 are being replaced. why does changing the filter have any effect on the replacing portion of the regex?
i seem to be missing some very basic point about how mixing filtering and replacing stuff in one s command works.
回答1:
Your regex only replaces the 456 that is at the start of the string that only consists of digits.
You may use
s/(?:\G(?!^)|^(?=\d+$))\d*?\K456/999/g
See the regex demo
Pattern details
(?:\G(?!^)|^(?=\d+$))- a custom boundary that matches either the end of the previous successful match (\G(?!^)) or (|) the start of string (^) that only contains digits ((?=\d+$))\d*?- 0+ digits, but as few as possible\K- omit the currently matched chars456- a456substring.
The idea is:
- Use the
\Gbased pattern to pre-validate the string:(?:\G(?!^)|^(?=<YOUR_VALID_LINE_FORMAT>$)) - Then adjust the consuming pattern after the above one.
回答2:
Alternatively you can probably use (*SKIP)(*F) to skip strings not composed only of digits .
s/^\d*\D.*(*SKIP)(*F)|456/999/g
See this demo at regex101 or your demo at tio.run
The left part ^\d*\D.* tries to match any \D non digit. If found, skips .* rest of the string and fails | OR matches the specified substring 456.
来源:https://stackoverflow.com/questions/59283414/regex-how-to-replace-all-occurrences-of-a-string-within-another-string-if-the