9

I have a string foo_bar_not_needed_string_part_123. Now in this string I want to remove not_needed_string_part only when foo_ is followed by bar.

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.

7 Answers 7

6

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.

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

6 Comments

Nice, way to get this done. Thanks, for the redundant part info.
Can you clarify one thing is look-behind/look-ahead capturing or non-capturing. For:eq st=foobar and I use foo(?=bar) it will not capture bar in $1 unless I use foo(?=bar)(bar) than I have bar in $1. So, is there any way I can make them capturing.
The 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 follows foo, just use foo(bar) syntax without any lookahead checks: it will match only if foo is followed by bar.
@Noob: If you want to capture the value in look-ahead you can do foo(?=(bar)). Although the example you presented is redundant.
@raina77ow: this doesn't strictly match the requirement, as the OP said he wanted to retain the underscore before the trailing digits
|
6

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;

2 Comments

This sort of thing has long been superseded by look-ahead / look-behind
@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.
2

What's about to divide string to 3 parts, and delete only middle?

$str =~ s/(foo_(?=bar)bar_)(.*?)(_\d+)/$1$3/;

Comments

2

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+)//;

Comments

1

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.

Comments

1

Try this:

(?<=foo_bar_).*(?=_\d)

In this variant, it includes in result ALL (.*) between foo_bar_ and _"any digit".

In your regex, it includes in result:

foo_

Then it looks for "bar" after "foo_":

(?=bar)

But it DOES NOT included at this step. It is included on the next step:

bar_

And then rest of line is included by (.*?)_\d+.

So, in general: it includes in result all this that you typed, EXCEPT (?=bar), which is just looking for "bar" after expression.

1 Comment

I 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.
1

go with

echo "foo_bar_not_needed_string_part_123" | perl -pe 's/(?<=foo_bar_)[^\d]+//'

Comments

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.