Perl: How to replace only matched part of string?
Solution 1
There's another way, and it's quite simple:
my $str = "foo_bar_not_needed_string_part_123";
$str =~ s/(?<=foo_bar_)\D+//gi;
print $str;
The trick is to use lookbehind check anchor, and replace all non-digit symbols that follow this anchor (not a symbol). Basically, with this pattern you match only the symbols you need to be removed, hence no need for capturing groups.
As a sidenote, in the original regex (?=bar)bar
construct is redundant. The first part (lookahead) will match only if some position is followed by 'bar' - but that's exactly what's checked with non-lookahead part of the pattern.
Solution 2
You can capture the parts you do not want to remove:
my $str = "foo_bar_not_needed_string_part_123";
$str =~ s/(foo_bar_).*?(_\d+)/$1$2/;
print $str;
Solution 3
You can try this:
my $str = "foo_bar_not_needed_string_part_123";
say $str if $str =~ s/(foo_(?=bar)bar_).*?(_\d+)/$1$2/;
Outputs:
foo_bar__123
PS: I am new to perl/regex
so I am interested if there exist a way to directly replace the matched part. What I have done is captured everything which is required and than replaced the whole string with it.
Solution 4
go with
echo "foo_bar_not_needed_string_part_123" | perl -pe 's/(?<=foo_bar_)[^\d]+//'
Solution 5
You can use look-behind/look-ahead in this case
$str =~ s/(?<=foo_bar_).*?(?=_\d+)//;
and the look-behind can be replace with \K
(keep) to make it a little tidier
$str =~ s/foo_bar_\K.*?(?=_\d+)//;
RanRag
I am an undergraduate student who has completed his B-Tech in Information & Communication Technology(ICT), INDIA. I am just a normal guy who has recently found interest in programming. Initially I was a big Java fan but now I am a Python enthusiast. Currently, exploring Android App Development.
Updated on July 09, 2022Comments
-
RanRag almost 2 years
I have a string
foo_bar_not_needed_string_part_123
. Now in this string I want to removenot_needed_string_part
only whenfoo_
is followed bybar
.I used the below regex:
my $str = "foo_bar_not_needed_string_part_123"; say $str if $str =~ s/foo_(?=bar)bar_(.*?)_\d+//;
But it removed the whole string and just prints a newline.
So, what I need is to remove only the matched (.*?) part. So, that the output is
foo_bar__123.
-
RanRag over 11 yearsNice, way to get this done. Thanks, for the redundant part info.
-
RanRag over 11 yearsCan you clarify one thing is
look-behind/look-ahead
capturing or non-capturing. For:eqst=foobar
and I usefoo(?=bar)
it will not capturebar
in$1
unless I usefoo(?=bar)(bar)
than I havebar
in$1
. So, is there any way I can make them capturing. -
Gene D. over 11 yearsI can't comment not mine post, but anyway: foo(?=bar)(bar) has no sense, since it looks for "bar" after "foo" (but DOES NOT includes it, just looking, if "bar" is here, then "foo" included in result, if "bar" is absent, then "foo" does not included), and then includes bar. foo(bar) should works fine, "bar" will be in $1.
-
raina77ow over 11 yearsThe construct
(?=%pattern%)%pattern%
is redundant by definition: it's the same as ([a-c]|a|b|c
), for example. In both cases you check for the same pattern twice. If you need to capture the part that followsfoo
, just usefoo(bar)
syntax without any lookahead checks: it will match only iffoo
is followed bybar
. -
RanRag over 11 years@Noob: If you want to capture the value in look-ahead you can do
foo(?=(bar))
. Although the example you presented is redundant. -
Borodin over 11 years@raina77ow: this doesn't strictly match the requirement, as the OP said he wanted to retain the underscore before the trailing digits
-
Borodin over 11 yearsThis sort of thing has long been superseded by look-ahead / look-behind
-
raina77ow over 11 years@Borodin That would be quite easy to fix (the easiest is just to change
...\D+//gi
to...\D+/_/gi
). But I thought it was actually an artifact of the code given in the question, and not the real intent. ) -
Breiz almost 11 years@Borodin, yes and no. Lookbehind has some serious limitations (e.g. many regex flavors, including those used by Perl and Python, only allow fixed-length strings) and I'm glad that tanguy mentioned this too.