perlreapi - Perl 正则表达式插件接口
从 Perl 5.9.5 开始,提供了一种新的接口,用于插入和使用除默认正则表达式引擎之外的其他引擎。
每个引擎都应该提供对以下格式的常量结构的访问
typedef struct regexp_engine {
REGEXP* (*comp) (pTHX_
const SV * const pattern, const U32 flags);
I32 (*exec) (pTHX_
REGEXP * const rx,
char* stringarg,
char* strend, char* strbeg,
SSize_t minend, SV* sv,
void* data, U32 flags);
char* (*intuit) (pTHX_
REGEXP * const rx, SV *sv,
const char * const strbeg,
char *strpos, char *strend, U32 flags,
struct re_scream_pos_data_s *data);
SV* (*checkstr) (pTHX_ REGEXP * const rx);
void (*free) (pTHX_ REGEXP * const rx);
void (*numbered_buff_FETCH) (pTHX_
REGEXP * const rx,
const I32 paren,
SV * const sv);
void (*numbered_buff_STORE) (pTHX_
REGEXP * const rx,
const I32 paren,
SV const * const value);
I32 (*numbered_buff_LENGTH) (pTHX_
REGEXP * const rx,
const SV * const sv,
const I32 paren);
SV* (*named_buff) (pTHX_
REGEXP * const rx,
SV * const key,
SV * const value,
U32 flags);
SV* (*named_buff_iter) (pTHX_
REGEXP * const rx,
const SV * const lastkey,
const U32 flags);
SV* (*qr_package)(pTHX_ REGEXP * const rx);
#ifdef USE_ITHREADS
void* (*dupe) (pTHX_ REGEXP * const rx, CLONE_PARAMS *param);
#endif
REGEXP* (*op_comp) (...);
当正则表达式被编译时,它的engine
字段会被设置为指向相应的结构,这样当需要使用它时,Perl 就可以找到正确的例程来执行。
为了安装新的正则表达式处理程序,$^H{regcomp}
被设置为一个整数,该整数(在适当的类型转换后)解析为这些结构之一。在编译时,comp
方法被执行,并且生成的 regexp
结构的 engine 字段应该指向同一个结构。
定义中的 pTHX_ 符号是 Perl 在多线程环境下使用的宏,用于向例程提供一个额外的参数,该参数指向正在执行正则表达式的解释器。因此,在多线程环境下,所有例程都会获得一个额外的参数。
REGEXP* comp(pTHX_ const SV * const pattern, const U32 flags);
使用给定的 flags
编译存储在 pattern
中的模式,并返回指向已准备好的 REGEXP
结构的指针,该结构可以执行匹配。有关 REGEXP 结构中各个字段的说明,请参见下面的 "REGEXP 结构"。
pattern
参数是作为模式使用的标量。Perl 的早期版本会传递两个 char*
,分别表示字符串化模式的开始和结束;可以使用以下代码段获取旧的参数
STRLEN plen;
char* exp = SvPV(pattern, plen);
char* xend = exp + plen;
由于任何标量都可以作为模式传递,因此可以实现一个引擎,该引擎对数组("ook" =~ [ qw/ eek hlagh / ]
)或编译正则表达式的非字符串化形式("ook" =~ qr/eek/
)执行某些操作。Perl 自身的引擎总是使用上面的代码段将所有内容字符串化,但这并不意味着其他引擎也必须这样做。
flags
参数是一个位域,它指示正则表达式是用哪些 msixpn
标志编译的。它还包含其他信息,例如 use locale
是否生效。
eogc
标志在传递给 comp 例程之前会被剥离。正则表达式引擎不需要知道是否设置了这些标志,因为这些标志应该只影响 Perl 对模式及其匹配变量的操作,而不是影响它的编译和执行方式。
在调用 comp 回调之前,其中一些标志已经生效(在适用的地方进行了说明)。但是,它们的大部分影响是在 comp 回调运行之后发生的,在读取 rx->extflags
字段的例程中,该字段由它填充。
通常情况下,标志应该在编译后保留在rx->extflags
中,尽管正则表达式引擎可能需要添加或删除一些标志来调用或禁用 Perl 中的一些特殊行为。标志及其导致的任何特殊行为将在下面进行说明。
模式修饰符
/m
- RXf_PMf_MULTILINE如果此标志存在于rx->extflags
中,它将由pp_split
传递给Perl_fbm_instr
,后者将把目标字符串视为多行字符串。
/s
- RXf_PMf_SINGLELINE/i
- RXf_PMf_FOLD/x
- RXf_PMf_EXTENDED如果在正则表达式中存在,"#"
注释在某些情况下将由词法分析器以不同的方式处理。
待办事项:记录这些情况。
/p
- RXf_PMf_KEEPCOPY待办事项:记录此标志。
字符集规则由此字段中包含的枚举确定。这仍然是实验性的,可能会发生变化,但当前接口使用内联函数get_regex_charset(const U32 flags)
返回规则。目前唯一记录的返回值是 REGEX_LOCALE_CHARSET,如果use locale
生效,则会设置此值。如果存在于rx->extflags
中,split
将在 RXf_SKIPWHITE 或 RXf_WHITE 生效时使用与区域设置相关的空格定义。ASCII 空格定义为根据isSPACE,以及在 UTF-8 下的内部宏is_utf8_space
,以及在use locale
下的isSPACE_LC
。
其他标志
此标志已在 perl 5.18.0 中移除。split ' '
现在仅在解析器中被特殊处理。RXf_SPLIT 仍然被 #defined,因此您可以测试它。以下是它以前的工作方式
如果split
被调用为split ' '
或没有参数(实际上意味着split(' ', $_)
,请参阅split),Perl 将设置此标志。然后正则表达式引擎可以检查它并设置 SKIPWHITE 和 WHITE 扩展标志。为此,Perl 引擎执行以下操作
if (flags & RXf_SPLIT && r->prelen == 1 && r->precomp[0] == ' ')
r->extflags |= (RXf_SKIPWHITE|RXf_WHITE);
这些标志可以在编译期间设置,以在split
操作符中启用优化。
此标志在 Perl 5.18.0 中已被移除。它仍然被 #defined,因此您可以设置它,但这样做不会有任何效果。以下是它以前的工作方式
如果该标志存在于 rx->extflags
中,split
将在操作之前从目标字符串的开头删除空格。空格的定义取决于目标字符串是否为 UTF-8 字符串以及是否设置了 RXf_PMf_LOCALE
标志。
如果除了此标志之外还设置了 RXf_WHITE,split
的行为将类似于 Perl 引擎下的 split " "
。
告诉 split 操作符在换行符 (\n
) 上分割目标字符串,而无需调用正则表达式引擎。
如果模式为 /^/
(plen == 1 && *exp == '^'
),即使在 /^/s
下,Perl 引擎也会设置此标志;请参阅 split。当然,不同的正则表达式引擎可能希望使用不同的语法来实现相同的优化。
告诉 split 操作符在空格上分割目标字符串,而无需调用正则表达式引擎。空格的定义取决于目标字符串是否为 UTF-8 字符串以及是否设置了 RXf_PMf_LOCALE。
如果模式为 \s+
,Perl 引擎将设置此标志。
告诉 split 操作符在字符上分割目标字符串。字符的定义取决于目标字符串是否为 UTF-8 字符串。
Perl 引擎在空模式下设置此标志,此优化使 split //
比其他方式快得多。它甚至比 unpack
更快。
在 Perl 5.18.0 中添加,此标志表示正则表达式可能会执行与就地替换冲突的操作。例如,它可能包含后顾,或在匹配期间分配给非魔术变量(例如 $REGMARK 和 $REGERROR)。s///
在设置此标志时将跳过某些优化。
I32 exec(pTHX_ REGEXP * const rx,
char *stringarg, char* strend, char* strbeg,
SSize_t minend, SV* sv,
void* data, U32 flags);
执行正则表达式。参数为
要执行的正则表达式。
这是要匹配的 SV。请注意,实际要匹配的字符数组由下面描述的参数提供;SV 仅用于确定 UTF8 性质、pos()
等。
指向字符串物理起始位置的指针。
指向字符串物理结束位置后的字符的指针(即 \0
,如果有的话)。
指向字符串中应开始匹配的位置的指针;它可能不等于 strbeg
(例如在 /.../g
的后续迭代中)。
字符串的最小长度(以从 stringarg
开始的字节数衡量),必须匹配;如果引擎到达匹配的末尾但尚未到达字符串中的此位置,则应失败。
优化数据;可能会发生变化。
优化标志;可能会发生变化。
char* intuit(pTHX_
REGEXP * const rx,
SV *sv,
const char * const strbeg,
char *strpos,
char *strend,
const U32 flags,
struct re_scream_pos_data_s *data);
找到应尝试进行正则表达式匹配的起始位置,或者如果正则表达式引擎不应该运行因为模式无法匹配,则可能找到该位置。根据 regexp
结构的 extflags
成员的值,核心会适当地调用它。
参数
rx: the regex to match against
sv: the SV being matched: only used for utf8 flag; the string
itself is accessed via the pointers below. Note that on
something like an overloaded SV, SvPOK(sv) may be false
and the string pointers may point to something unrelated to
the SV itself.
strbeg: real beginning of string
strpos: the point in the string at which to begin matching
strend: pointer to the byte following the last char of the string
flags currently unused; set to 0
data: currently unused; set to NULL
SV* checkstr(pTHX_ REGEXP * const rx);
返回一个包含必须出现在模式中的字符串的 SV。由 split
用于优化匹配。
void free(pTHX_ REGEXP * const rx);
当 Perl 释放正则表达式模式时,Perl 会调用它,以便引擎可以释放 regexp
结构的 pprivate
成员指向的任何资源。这仅负责释放私有数据;Perl 将负责释放 regexp
结构中包含的任何其他内容。
用于获取/设置 $`
、$'
、$&
及其命名等效项的值,即 ${^PREMATCH}、${^POSTMATCH} 和 ${^MATCH},以及编号捕获组($1
、$2
、...)。
paren
参数对于 $1
为 1
,对于 $2
为 2
,依此类推,并且对于特殊变量具有以下符号值
${^PREMATCH} RX_BUFF_IDX_CARET_PREMATCH
${^POSTMATCH} RX_BUFF_IDX_CARET_POSTMATCH
${^MATCH} RX_BUFF_IDX_CARET_FULLMATCH
$` RX_BUFF_IDX_PREMATCH
$' RX_BUFF_IDX_POSTMATCH
$& RX_BUFF_IDX_FULLMATCH
请注意,在 Perl 5.17.3 及更早版本中,最后三个常量也用于变量的插入符号变体。
这些名称是根据 Tie::Scalar 方法名称类推选择的,并添加了 LENGTH 回调以提高效率。但是,命名捕获变量目前没有在内部绑定,而是通过魔术实现的。
void numbered_buff_FETCH(pTHX_ REGEXP * const rx, const I32 paren,
SV * const sv);
获取指定编号的捕获。sv
应该设置为要返回的标量,标量作为参数传递而不是从函数返回,因为当它被调用时,Perl 已经有一个标量来存储值,创建另一个标量将是多余的。标量可以使用 sv_setsv
、sv_setpvn
等设置,请参见 perlapi。
此回调是在 Perl 在 taint 模式下解除自身捕获变量的 taint 时(参见 perlsec)。有关如何在 taint 模式下解除捕获变量的 taint,请参见 regcomp.c 中的 Perl_reg_numbered_buff_fetch
函数,如果您希望您的引擎也执行此操作。
void (*numbered_buff_STORE) (pTHX_
REGEXP * const rx,
const I32 paren,
SV const * const value);
设置编号捕获变量的值。value
是将用作新值的标量。引擎需要确保将其用作新值(或拒绝它)。
示例
if ("ook" =~ /(o*)/) {
# 'paren' will be '1' and 'value' will be 'ee'
$1 =~ tr/o/e/;
}
Perl 自身的引擎将在任何尝试修改捕获变量的操作上抛出异常,要在另一个引擎中执行此操作,请使用以下回调(从 Perl_reg_numbered_buff_store
复制)
void
Example_reg_numbered_buff_store(pTHX_
REGEXP * const rx,
const I32 paren,
SV const * const value)
{
PERL_UNUSED_ARG(rx);
PERL_UNUSED_ARG(paren);
PERL_UNUSED_ARG(value);
if (!PL_localizing)
Perl_croak(aTHX_ PL_no_modify);
}
实际上,Perl 不会总是在看起来会修改编号捕获变量的语句中抛出异常。这是因为如果 Perl 可以确定它不需要修改值,则不会调用 STORE 回调。这正是绑定变量在相同情况下表现的方式
package CaptureVar;
use parent 'Tie::Scalar';
sub TIESCALAR { bless [] }
sub FETCH { undef }
sub STORE { die "This doesn't get called" }
package main;
tie my $sv => "CaptureVar";
$sv =~ y/a/b/;
因为当 y///
操作应用于 $sv
时,$sv
为 undef
,所以转换实际上不会执行,程序也不会 die
。这与 5.8 及更早版本的行为不同,因为捕获变量当时是 READONLY 变量;现在,它们在默认引擎中被赋值时只会 die
。
I32 numbered_buff_LENGTH (pTHX_
REGEXP * const rx,
const SV * const sv,
const I32 paren);
获取捕获变量的 length
。为此有一个特殊的回调,这样 Perl 不必执行 FETCH 并对结果运行 length
,因为长度(在 Perl 的情况下)是从 rx->offs
中存储的偏移量中知道的,这效率更高
I32 s1 = rx->offs[paren].start;
I32 s2 = rx->offs[paren].end;
I32 len = t1 - s1;
在 UTF-8 的情况下,这会稍微复杂一些,请参见 Perl_reg_numbered_buff_length
使用 is_utf8_string_loclen 的方式。
用于获取/设置 %+
和 %-
的值,以及 re 中的一些实用程序函数。
有两个回调函数,named_buff
在所有 FETCH、STORE、DELETE、CLEAR、EXISTS 和 SCALAR Tie::Hash 回调函数会被调用,这些回调函数会在对 %+
和 %-
进行更改时被调用,而 named_buff_iter
则在与 FIRSTKEY 和 NEXTKEY 相同的情况下被调用。
flags
参数可以用来确定回调函数应该响应哪些操作。目前定义了以下标志:
从 Perl 层面对 %+
或 %-
执行的 Tie::Hash 操作,如果有的话。
RXapif_FETCH
RXapif_STORE
RXapif_DELETE
RXapif_CLEAR
RXapif_EXISTS
RXapif_SCALAR
RXapif_FIRSTKEY
RXapif_NEXTKEY
如果对 %+
或 %-
进行了操作,如果有的话。
RXapif_ONE /* %+ */
RXapif_ALL /* %- */
如果这是作为 re::regname
、re::regnames
或 re::regnames_count
被调用,如果有的话。前两个将与 RXapif_ONE
或 RXapif_ALL
结合使用。
RXapif_REGNAME
RXapif_REGNAMES
RXapif_REGNAMES_COUNT
在内部,%+
和 %-
是通过 Tie::Hash::NamedCapture 使用真正的绑定接口实现的。该包中的方法将回调到这些函数。但是,将 Tie::Hash::NamedCapture 用于此目的的方式可能会在将来的版本中发生变化。例如,这可以通过魔法来实现(需要对 mgvtbl 进行扩展)。
SV* (*named_buff) (pTHX_ REGEXP * const rx, SV * const key,
SV * const value, U32 flags);
SV* (*named_buff_iter) (pTHX_
REGEXP * const rx,
const SV * const lastkey,
const U32 flags);
SV* qr_package(pTHX_ REGEXP * const rx);
qr// 魔法对象被祝福到的包(如 ref qr//
所示)。建议引擎将此更改为其包名以进行识别,无论它们是否在对象上实现方法。
此方法返回的包也应该在其 @ISA
中包含内部 Regexp
包。qr//->isa("Regexp")
应该始终为真,无论使用哪个引擎。
示例实现可能是
SV*
Example_qr_package(pTHX_ REGEXP * const rx)
{
PERL_UNUSED_ARG(rx);
return newSVpvs("re::engine::Example");
}
对使用 qr//
创建的对象进行的任何方法调用都将作为普通对象分派到该包。
use re::engine::Example;
my $re = qr//;
$re->meth; # dispatched to re::engine::Example::meth()
要在 XS 函数中从标量中检索 REGEXP
对象,请使用 SvRX
宏,请参阅 "perlapi 中的 REGEXP 函数"。
void meth(SV * rv)
PPCODE:
REGEXP * re = SvRX(sv);
void* dupe(pTHX_ REGEXP * const rx, CLONE_PARAMS *param);
在多线程构建中,可能需要复制正则表达式,以便多个线程可以使用该模式。此例程预计会处理对 regexp
结构的 pprivate
成员指向的任何私有数据的复制。它将使用预先构建的新 regexp
结构作为参数调用,pprivate
成员将指向旧的私有结构,并且此例程的责任是构建一个副本并返回指向它的指针(Perl 将使用它来覆盖传递给此例程的字段)。
这允许引擎复制其私有数据,并且如果需要,还可以修改最终结构,如果它确实必须这样做。
在非多线程构建中,此字段不存在。
这是 Perl 内核的私有内容,可能会发生变化。应保留为空。
REGEXP 结构在 regexp.h 中定义。所有正则表达式引擎都必须能够在其 "comp" 例程中正确构建这样的结构。
REGEXP 结构包含 Perl 需要知道的所有数据,以便正确地使用正则表达式。它包括有关 Perl 可以用来确定是否应该真正使用正则表达式引擎的优化的数据,以及在各种上下文中正确执行模式所需的各种其他控制信息,例如模式是否以某种方式锚定,或者在编译期间使用了哪些标志,或者程序是否包含 Perl 需要知道的特殊结构。
此外,它还包含两个字段,用于编译模式的正则表达式引擎的私有使用。它们是 intflags
和 pprivate
成员。pprivate
是指向任意结构的 void 指针,其使用和管理由编译引擎负责。Perl 永远不会修改这两个值中的任何一个。
typedef struct regexp {
/* what engine created this regexp? */
const struct regexp_engine* engine;
/* what re is this a lightweight copy of? */
struct regexp* mother_re;
/* Information about the match that the Perl core uses to manage
* things */
U32 extflags; /* Flags used both externally and internally */
I32 minlen; /* mininum possible number of chars in */
string to match */
I32 minlenret; /* mininum possible number of chars in $& */
U32 gofs; /* chars left of pos that we search from */
/* substring data about strings that must appear
in the final match, used for optimisations */
struct reg_substr_data *substrs;
U32 nparens; /* number of capture groups */
/* private engine specific data */
U32 intflags; /* Engine Specific Internal flags */
void *pprivate; /* Data private to the regex engine which
created this object. */
/* Data about the last/current match. These are modified during
* matching*/
U32 lastparen; /* highest close paren matched ($+) */
U32 lastcloseparen; /* last close paren matched ($^N) */
regexp_paren_pair *offs; /* Array of offsets for (@-) and
(@+) */
char *subbeg; /* saved or original string so \digit works
forever. */
SV_SAVED_COPY /* If non-NULL, SV which is COW from original */
I32 sublen; /* Length of string pointed by subbeg */
I32 suboffset; /* byte offset of subbeg from logical start of
str */
I32 subcoffset; /* suboffset equiv, but in chars (for @-/@+) */
/* Information about the match that isn't often used */
I32 prelen; /* length of precomp */
const char *precomp; /* pre-compilation regular expression */
char *wrapped; /* wrapped version of the pattern */
I32 wraplen; /* length of wrapped */
I32 seen_evals; /* number of eval groups in the pattern - for
security checks */
HV *paren_names; /* Optional hash of paren names */
/* Refcount of this regexp */
I32 refcnt; /* Refcount of this regexp */
} regexp;
这些字段将在下面更详细地讨论。
engine
此字段指向一个 regexp_engine
结构,该结构包含指向用于执行匹配的子例程的指针。编译例程有责任在返回正则表达式对象之前填充此字段。
在内部,除非在 $^H{regcomp}
中指定了自定义引擎,否则它被设置为 NULL
,Perl 自己的回调集可以在 RE_ENGINE_PTR
指向的结构中访问。
mother_re
待办事项,请参阅提交 28d8d7f41a。
extflags
Perl 将使用此字段来查看正则表达式编译时使用的标志,通常情况下,此字段将由 comp 回调函数设置为 flags 参数的值。有关有效标志,请参阅 comp 文档。
minlen
minlenret
模式匹配所需的最小字符串长度(以字符为单位)。这用于修剪搜索空间,避免在字符串末尾进行匹配,因为这样做不会比允许匹配更接近字符串末尾。例如,如果 minlen 为 10 但字符串只有 5 个字符长,则没有必要启动正则表达式引擎。模式不可能匹配。
minlenret
是匹配后在 $& 中找到的字符串的最小长度(以字符为单位)。
以下模式可以看出 minlen
和 minlenret
之间的区别
/ns(?=\d)/
其中 minlen
为 3,但 minlenret
仅为 2,因为 \d 需要匹配,但实际上不包含在匹配的内容中。这种区别尤其重要,因为替换逻辑使用 minlenret
来判断是否可以进行就地替换(这会导致速度大幅提升)。
gofs
从 pos() 开始匹配的左侧偏移量。
substrs
有关必须出现在最终匹配中的字符串的子字符串数据。目前,这仅在 Perl 引擎内部使用,但将来可能会用于所有引擎进行优化。
nparens
、lastparen
和 lastcloseparen
这些字段用于跟踪:模式中包含多少个括号捕获组;哪个是最高级别的已关闭括号(请参阅 "$+" in perlvar);以及哪个是最新的已关闭括号(请参阅 "$^N" in perlvar)。
intflags
引擎对模式编译时使用的标志的私有副本。通常情况下,此字段与 extflags
相同,除非引擎选择修改其中一个标志。
pprivate
指向引擎定义的数据结构的 void*。Perl 引擎使用 regexp_internal
结构(请参阅 "Base Structures" in perlreguts),但自定义引擎应该使用其他结构。
offs
一个 regexp_paren_pair
结构,它定义了匹配字符串中的偏移量,这些偏移量对应于 $&
和 $1
、$2
等捕获,regexp_paren_pair
结构定义如下:
typedef struct regexp_paren_pair {
I32 start;
I32 end;
} regexp_paren_pair;
如果 ->offs[num].start
或 ->offs[num].end
为 -1
,则该捕获组未匹配。->offs[0].start/end
代表 $&
(或 ${^MATCH}
在 /p
下),->offs[paren].end
匹配 $$paren
,其中 $paren
= 1>。
precomp
prelen
用于优化。precomp
保存了编译后的模式的副本,prelen
是它的长度。当要编译一个新的模式(例如在循环中)时,内部 regcomp
运算符会检查最后一个编译的 REGEXP
的 precomp
和 prelen
是否与新的模式等效,如果是,则使用旧的模式而不是编译一个新的模式。
来自 Perl_pp_regcomp
的相关代码片段
if (!re || !re->precomp || re->prelen != (I32)len ||
memNE(re->precomp, t, len))
/* Compile a new pattern */
paren_names
这是一个内部用于跟踪命名捕获组及其偏移量的哈希表。键是缓冲区的名称,值是双变量,IV 槽位保存具有给定名称的缓冲区数量,pv 是一个嵌入的 I32 数组。当使用命名反向引用时,这些值也可以独立地包含在数据数组中。
substrs
保存有关必须从模式开头开始的固定偏移量处出现的最长字符串和必须从模式开头开始的浮动偏移量处出现的最长字符串的信息。用于对字符串进行快速 Boyer-Moore 搜索,以确定是否值得使用正则表达式引擎,以及如果值得,则在字符串的哪个位置进行搜索。
subbeg
sublen
saved_copy
suboffset
subcoffset
在执行阶段用于管理搜索和替换模式,以及提供 $&
、$1
等的文本。subbeg
指向一个缓冲区(原始字符串或 RX_MATCH_COPIED(rx)
情况下的副本),sublen
是缓冲区的长度。RX_OFFS
的开始和结束索引索引到此缓冲区。
如果设置了 REXEC_COPY_STR
标志,但同时设置了 REXEC_COPY_SKIP_PRE
或 REXEC_COPY_SKIP_POST
标志,引擎可以选择不复制整个缓冲区(尽管在 RXf_PMf_KEEPCOPY
设置或 PL_sawampersand
中设置了相关位的情况下,仍然必须复制)。在这种情况下,引擎可以设置 suboffset
来指示从缓冲区逻辑起始位置到物理起始位置的字节数(即 subbeg
)。它还应该设置 subcoffset
,即偏移量中的字符数。后者是支持 @-
和 @+
所必需的,因为它们以字符而不是字节为单位工作。
wrapped
wraplen
存储字符串 qr//
转换为的字符串。例如,Perl 引擎在 qr/eek/
的情况下存储 (?^:eek)
。
当使用不支持 (?:)
结构进行内联修饰符的自定义引擎时,最好让 qr//
转换为提供的模式,注意这将在以下情况下创建不希望的模式:
my $x = qr/a|b/; # "a|b"
my $y = qr/c/i; # "c"
my $z = qr/$x$y/; # "a|bc"
除了让自定义引擎理解类似 (?:)
的结构之外,没有其他解决方案可以解决这个问题。
seen_evals
它存储模式中 eval 组的数量。这在将编译后的正则表达式嵌入到使用 qr//
的更大模式中时用于安全目的。
refcnt
结构被引用的次数。当此值降至 0 时,正则表达式将通过调用 pregfree
自动释放。这应该在每个引擎的 "comp" 例程中设置为 1。
最初是 perlreguts 的一部分。
最初由 Yves Orton 编写,由 Ævar Arnfjörð Bjarmason 扩展。
版权所有 2006 Yves Orton 和 2007 Ævar Arnfjörð Bjarmason。
本程序是自由软件;您可以根据与 Perl 本身相同的条款重新分发和/或修改它。