Perl's regex engine doesn't search from the end, but you can anchor your match at the end to make it backtrack. See perlre.
perl -Dr -e '
@l = ("A".."Z","a".."z",qw(< / >),0..9);
$_ = join( "", map { $l[ rand @l ] } 1 .. 100_000 )
. "</body></html>";
s|(</body></html>)$|zzz$1|
'
Compiling REx "(</body></html>)$"
rarest char < at 0
Final program:
1: OPEN1 (3)
3: EXACT <</body></html>> (8)
8: CLOSE1 (10)
10: EOL (11)
11: END (0)
anchored "</body></html>"$ at 0 (checking anchored) minlen 14
Omitting $` $& $' support.
EXECUTING...
Guessing start of match in sv for REx "(</body></html>)$" against "Fw3
+EK>>Y6x<q>x4s7sACk6xtpG9etod1O4uibfbVBwJNJLRurKYn>SdVRt2o"...
Found anchored substr "</body></html>"$ at offset 100000...
Starting position does not contradict /^/m...
Guessed: match at offset 100000
Matching REx "(</body></html>)$" against "</body></html>"
100000 <yUnOt> <</body></h> | 1:OPEN1(3)
100000 <yUnOt> <</body></h> | 3:EXACT <</body></html>>(8)
100014 <body></html>> <> | 8:CLOSE1(10)
100014 <body></html>> <> | 10:EOL(11)
100014 <body></html>> <> | 11:END(0)
Match successful!
Freeing REx: "(</body></html>)$"
As you see, the anchor will be checked first, and then the rest is quite inexpensive. Small benchmark...
use Benchmark qw(cmpthese);
@l = ("A".."Z","a".."z",qw(< / >),0..9);
$x = join( '', map { $l[ rand @l ] } 1 .. 100_000 ) . "</body></html>"
+;
cmpthese ( -1,
{
noanchor => sub { local $_ = $x; s|(</body></html>)|zzz$1| },
anchor => sub { local $_ = $x; s|(</body></html>)$|zzz$1| },
}
);
Rate noanchor anchor
noanchor 5023/s -- -19%
anchor 6222/s 24% --
|