What I'm trying to do seems deceptively simple, but I can't find a way to make it work.
I want to match a number, capture it, and then match the following N characters in the string. Naively, I thought something like this would work:
$myString = "1abc3cdf\n";
# Capture the number, and use a back-reference in the {} to define how many characters to match
$myString =~ s/(\d+).{\1}//g;
print $myString;
I expect to get bc
, but it just returns the original string 1abc3cdf
, ie no substitution has taken place.
I tried with an extended regex (ie s///ge
) but that didn't help. Any suggestions?
You may use the (??{...})
inline code block:
$myString =~ s/(\d+)(??{ ".{$^N}" })//g;
See the Perl demo.
Here is some reference:
This is a "postponed" regular subexpression. It behaves in exactly the same way as a
(?{ code })
code block as described above, except that its return value, rather than being assigned to$^R
, is treated as a pattern, compiled if it's a string (or used as-is if its a qr// object), then matched as if it were inserted instead of this construct.During the matching of this sub-pattern, it has its own set of captures which are valid during the sub-match, but are discarded once control returns to the main pattern.
And here is more about the whole regex:
(\d+)
- Capturing group #1 that matches any one or more digits(??{ ".{$^N}" })
- a code block that represents "a "postponed" regular subexpression" whose return value is "treated as a pattern, compiled if it's a string". The "$^N
contains whatever was matched by the most-recently closed group (submatch)" (see the perlre reference). In other words, if (\d+)
captures 45
, the (??{ ".{$^N}" })
turns into .{45}
and thus matches any 45 characters other than line break characters.