bug-sed
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#31816: Saved Sub String Only Saves Last


From: Eric Blake
Subject: bug#31816: Saved Sub String Only Saves Last
Date: Mon, 18 Jun 2018 15:04:23 -0500
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0

tag 31816 notabug
thanks

On 06/13/2018 12:03 PM, Mark Otto wrote:
If I use a saved substring it should capture the maximum number of
characters that fit the pattern, in this case  [0-9][0-9]*.

Sed already does that (an operator is as greedy as possible, given what has already been matched earlier in the line). However, you are misunderstanding how greedy operators work.


echo "I'm 2254 years old"|sed "s/^..*\([0-9][0-9]*\) /She's \1 /"
She's 4 years old"

That is correct output. Remember, in sed, every pattern is evaluated from left to right to find the longest possible substring that will match, where patterns on the left use a shorter substring only if patterns on the right are not possible with the longest substring. Since .* is a greedy pattern, you have matched:

"I" "'m 225" "4"
 ^.  .*       \([0-9][0-9]*\)



She should be 2254 years old.

If you want the second pattern to match longer as a higher priority than the first .* pattern being greedy, you have to use some other pattern on the first use, such as:

echo "I'm 2254 years old" | sed "s/^..*[^0-9]\([0-9][0-9]*\)/She's \1/"

which matches as:

"I" "'m" " "     "2254"
 ^.  .*   [^0-9]  \([0-9][0-9]*\)

where my explicit match of a non-digit forced the .* to be less greedy.

Or, you can use other languages, like perl, which have the extension of non-greedy operators, as in:

echo "I'm 2254 years old" | perl -pe "s/^..*?([0-9]+) /She's \1/"

perl is more like 'sed -E', but has the additional '.*?' non-greedy counterpart to '.*' that sed lacks.


It does search correctly because without the substring it replaces all the
digits:

echo "I'm 2287 years old"|sed "s/^..*[0-9][0-9]*/She's many/"
She's many years old"

That output is still correct, but wasn't doing what you claimed it was doing. Again, it was matching:

"I" "'m 228" "7"
 ^.  .*       [0-9][0-9]*

then replacing that entire match.

As such, I'm marking this as not a bug. But feel free to comment further if you still need help.

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org





reply via email to

[Prev in Thread] Current Thread [Next in Thread]