gpt4 book ai didi

perl - perl 是否缓存正则表达式生成?

转载 作者:行者123 更新时间:2023-12-03 21:30:13 24 4
gpt4 key购买 nike

假设我有一个动态生成正则表达式然后匹配它们的函数。

例如,在以下函数中 match_here \G anchor 插入到正则表达式的开头。这简化了 API,因为调用者不需要记住包含 pos anchor 定在图案中。

#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use Data::Dumper;

sub match_here {
my ($str, $index, $rg) = @_;
pos($str) = $index;
croak "index ($index) out of bounds" unless pos($str) == $index;
my $out;
if ($str =~ /\G$rg/) {
$out = $+[0];
}
return $out;
}

# no match starting at position 0
# prints '$VAR1 = undef;'
print Dumper(match_here("abc", 0, "b+"));
# match from 1 to 2
# prints '$VAR1 = 2;'
print Dumper(match_here("abc", 1, "b+"));

我想知道每次评估函数时是否都会“编译”匿名正则表达式对象,或者是否有一些缓存以便相同的字符串不会导致编译额外的正则表达式对象。

另外,假设 Perl 解释器没有进行缓存,编译正则表达式对象是否足够昂贵以值得缓存(可能在 XS 扩展中)?

最佳答案

来自 perlop (1)、下m//运算符(operator):

PATTERN may contain variables, which will be interpolated every time the pattern search is evaluated

[...]

Perl will not recompile the pattern unless an interpolated variable that it contains changes. You can force Perl to skip the test and never recompile by adding a "/o" (which stands for "once") after the trailing delimiter. Once upon a time, Perl would recompile regular expressions unnecessarily, and this modifier was useful to tell it not to do so, in the interests of speed.


所以是的,有一个缓存,你甚至可以通过说 /o 强制使用缓存,即使它是无效的。 ,但你真的不应该那样做。
但是该缓存仅为 m// 的每个实例存储一个已编译的正则表达式。或 s///运算符,因此只有在 regexp 连续多次与相同的变量(例如您的 $rg )一起使用时,它才有帮助。如果您交替使用 $rg='b+' 调用它和 $rg='c+'你每次都会得到一个重新编译。
对于这种情况,您可以使用 qr// 进行自己的缓存。运算符(operator)。它显式编译正则表达式并返回一个对象,您可以存储该对象并用于稍后执行正则表达式。这可以纳入您的 match_here像这样:
use feature 'state';

sub match_here {
my ($str, $index, $rg) = @_;
pos($str) = $index;
croak "index ($index) out of bounds" unless pos($str) == $index;
my $out;
state %rg_cache;
my $crg = $rg_cache{$rg} ||= qr/\G$rg/;
if ($str =~ /$crg/) {
$out = $+[0];
}
return $out;
}
添加更多关于基本缓存的细节(当不使用 qr// 时):事实是 $rg是一个新分配的词法变量,每次都没有区别。重要的是该值与前一个相同。
这里有一个例子来证明这一点:
use re qw(Debug COMPILE);

while(<>) {
chomp;
# Insane interpolation. Do not use anything remotely like this in real code
print "MATCHED: $_\n" if /^${\(`cat refile`)}/;
}
每次匹配运算符执行时,它都会读取 refile .正则表达式为 ^后面是 refile的内容.调试输出显示只有在文件内容发生更改时才重新编译它。如果文件仍然具有与上次相同的内容,则运算符(operator)会注意到再次将相同的字符串传递给正则表达式编译器,并重用缓存的结果。
或者试试这个不那么戏剧化的例子:
use re qw(Debug COMPILE);

@patterns = (
'\d{3}',
'\d{3}',
'[aeiou]',
'[aeiou]',
'\d{3}',
'\d{3}'
);

for ('xyz', '123', 'other') {
for $i (0..$#patterns) {
if(/$patterns[$i]/) {
print "$_ matches $patterns[$i]\n";
} else {
print "$_ does not match $patterns[$i]\n";
}
}
}
其中有 18 个编译,其中 11 个是缓存命中,即使相同的“变量”( @patterns 数组的相同元素)从未连续使用过两次。

关于perl - perl 是否缓存正则表达式生成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49227638/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com