5

I would like to ask if it is possible to put another regular expression inside the RHS of a substitution match expression with the "e" modifier.

For example, I would like to replace any occurrence of the word stored in $foo with the same number of "-", case insensitive.

For example:

$str =~ s/($foo)/$temp = $1; $temp ~= s/./-//gie;

But it constantly gives syntax error when compiling, while

$str =~ s/($foo)/$temp = $1; $temp = "---"/gie; 

does work.

I guess I did not properly escape the slashes, any ideas?

Vitt Volt
  • 337
  • 4
  • 17
  • just change the separator : `s/.../$&=~s%...%...%r/e` (you of course need the `/e` modifier). Your code is pretty strange though, maybe you should explain a little bit more what you're trying to do so we can help more. In particular, `$1` is undef, and even if it were defined, without the `/r` modifier, your nested regex is useless. – Dada Oct 25 '16 at 19:52
  • See [Replace pattern with one space per character in Perl](http://stackoverflow.com/q/17866072/176646) – ThisSuitIsBlackNot Oct 25 '16 at 19:57
  • Thanks a lot! The s%%%r expression worked well. This is exactly what I have been looking for which I did not find in other documents. – Vitt Volt Oct 25 '16 at 19:59
  • @VittVolt: The point of `%` is that it is a different delimiter from `/` used in the main enclosing regex. You may use other regex delimiters, too. – Wiktor Stribiżew Oct 25 '16 at 20:01

2 Answers2

6

You certainly need the e modifier to be able to use

$str = 'banana';
$foo = 'na';
$str =~ s/$foo/$&=~s#.#-#gr/ge;
print $str;

See the online Perl demo

Note that the outer regex uses / regex delimiters, while the inner one contains different ones (you can use your favorite two here).

The e modifier is obligatory with the outer pattern, and you also need to pass r modifier to the inner one to avoid Modification of a read-only value issue.

Also note that before Perl v.5.20, you'd better avoid $& and enclose the whole pattern with (...) capturing group:

$str =~ s/($foo)/$1=~s#.#-#gr/ge;
          ^    ^ ^^ 
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • cool, I always used to use a `sub` for such cases.. didn't think of using `r` flag... also `tr` can be used when needed with the same `r` flag – Sundeep Oct 26 '16 at 06:14
  • I am before using the method `$str=~s/$foo/my $tmp=$&; $tmp=~s#.#-#g; ($tmp);/ge;` However, `$str =~ s/($foo)/$1=~s#.#-#gr/ge;` is awesome of code. – ssr1012 Oct 26 '16 at 06:19
  • [`s/($foo)/'-' x length($1)/gie`](http://stackoverflow.com/a/40256454/133939) is less clumsy – Zaid Oct 26 '16 at 07:45
  • @Zaid: It won't work if you need to replace only specific subpattern from the matches. So, "clumsy" is not appropriate here, my answer is generic for the current problem (actually, I think OP is looking for such a generic solution, otherwise, I would close as a dupe of http://stackoverflow.com/q/17866072/176646). – Wiktor Stribiżew Oct 26 '16 at 07:50
  • @WiktorStribiżew Not sure what you mean by more complex tasks. Is it not possible to define `my $foo = "f..|t..";`? – Zaid Oct 26 '16 at 08:50
  • I think you're addressing a more generic scenario then, which the OP didn't require in this question (*"I would like to replace any occurrence of the word stored in $foo with the same number of "-", case insensitive."*). I had assumed this is what you were addressing, which is why I felt that `$1 =~ s#.#-#gr` was clumsier than `'-' x length($1)` – Zaid Oct 26 '16 at 10:08
0

Nesting a s/// inside another s/// isn't necessary here

I know this doesn't answer the question, but answers the need:

$_ = "footastic Funtastic Fantastic";
my $foo = "f..";
s/($foo)/'-' x length($1)/gie;
print;  # ---tastic ---tastic ---tastic
Community
  • 1
  • 1
Zaid
  • 36,680
  • 16
  • 86
  • 155
  • The solution is already referenced to in the [ThisSuitIsBlackNot's comment](http://stackoverflow.com/questions/40248541/perl-regular-expression-inside-regular-expression/40249679?noredirect=1#comment67759615_40248541). It cannot be expanded for more complex tasks. – Wiktor Stribiżew Oct 26 '16 at 07:53