如何验证用户输入中的 Perl 正则表达式?
How can I validate a Perl regex in user input?
我从假定有效的 perl 正则表达式值的用户那里得到了一个输入列表。
示例可以是:
\b[Bb]anana\b
\s*Apples[BANANA]\s+
是否有安全的方法来验证这些字符串?
首先,考虑您想让用户使用某种模式做多少事情。 Perl 正则表达式可以 运行 任意代码。
但是,要验证您可以将字符串用作模式而不会导致致命错误,您可以使用 qr//
运算符编译字符串并使用 return 正则表达式。如果出现问题,qr
会给您一个致命错误,您可以使用 eval
:
捕获该错误
my $pattern = eval { qr/$input/ };
如果您返回 undef
,该模式无效。而且,尽管问题中有评论,但有无数种方法可以制作无效模式。我知道,因为我一直都在手动输入它们,而且我没有 运行 想办法搞砸 :)
这不会将模式应用于字符串,但您可以使用 $pattern
进行匹配:
if( $pattern ) {
$target =~ $pattern; # or $target =~ m/$pattern/
}
嗯,验证正则表达式需要了解您期望的输入类型。正则表达式运算符与自动机接受的字符串集之间存在直接关系。
这里的问题是通常字符串集不是众所周知的或者指定的不正确,例如:
正则表达式中的基本运算符集是基本语言字符集(提供要操作的符号)和使事情变得复杂的运算符:这是替代方案 |
(select一个或另一个),连接(没有符号,因为两个正则表达式只是放在一起表示一组字符串来自一组,然后是一个字符串,这次来自第二组)和关闭,用 *
表示(这最后的意思是允许任何重复 --- 包括 none--- 来自前一组的字符串)。
绝对所有的正则表达式都可以作为一个(主要是更复杂的)表达式来处理,它只使用这三个运算符,仅此而已。例如,可以通过重复应用它的正则表达式来处理 +
运算符,并将 *
添加到第二个实例(用括号括起来以将其全部分组) ?
可选后缀可以通过以下规则处理 (regexp)? == (regexp|)
(使用或不使用它的替代方法)
-
|
表示另一种选择...您提供两组字符串,结果集是两组的并集。这意味着如果一个字符串属于一个或任何一个集合,它将被接受。
- 连接表示集合是通过评估两个集合的笛卡尔积来构建的。你需要做成对的字符串,从第一组中取出一个,从另一组中取出第二个,所有可能的组都是这样形成的。
- 闭包意味着将字符串构建为来自同一集合的一系列(可能为零)实例....这意味着您可以连接该集合中的任何实例。
这组规则将为您提供构成正则表达式的完整字符串集。这可以与您的想法一致(或不一致)...但是如果您的想法定义不明确,那么它将是您的正则表达式。
因此,作为结论,您要求一个通用程序来测试您自己的想法以及您如何设计正则表达式。有一个定理(称为 Pumping 定理)用于证明正则表达式和有限状态自动机的等价性。这是一项非常重要的成就,因为它允许您使用正则表达式进行高效的单次传递、字符串识别。如果深入研究这一点,您会发现可以编写一个工具,该工具可以从正则表达式系统地构建将被某些正则表达式接受的完整字符串集。不过这有一个问题,就是许多正则表达式会创建无限组字符串,这意味着该算法不会在有限时间内完成。
作为最后的评论,我可以告诉您,这使正则表达式成为 select 字符串的一个非常强大的工具。您可以使用正则表达式检测复杂的事情,例如,作为一串数字,该数字构成十进制形式的 23 的倍数,或者验证信用卡号码是否存在转录错误。
如果您需要对提供给您的内容保持完全的偏执,您可以使用 Safe 模块来限制可用于 eval()
上下文的操作码。
您可以根据自己的需要在 permit_only()
中添加或减去。
sub safestringeval ($) {
require Safe;
my $safe = Safe->new;
$safe->permit_only(qw/:base_core anonhash anonlist gvsv gv gelem padsv padav padhv padany/);
return $safe->reval($_[0], 1);
}
$regex = safestringeval('qr{'.$input.'}');
我真的不记得这个的用例所以我查了一下。 :) 允许输入的字符串包含实时转义序列。
我从假定有效的 perl 正则表达式值的用户那里得到了一个输入列表。 示例可以是:
\b[Bb]anana\b
\s*Apples[BANANA]\s+
是否有安全的方法来验证这些字符串?
首先,考虑您想让用户使用某种模式做多少事情。 Perl 正则表达式可以 运行 任意代码。
但是,要验证您可以将字符串用作模式而不会导致致命错误,您可以使用 qr//
运算符编译字符串并使用 return 正则表达式。如果出现问题,qr
会给您一个致命错误,您可以使用 eval
:
my $pattern = eval { qr/$input/ };
如果您返回 undef
,该模式无效。而且,尽管问题中有评论,但有无数种方法可以制作无效模式。我知道,因为我一直都在手动输入它们,而且我没有 运行 想办法搞砸 :)
这不会将模式应用于字符串,但您可以使用 $pattern
进行匹配:
if( $pattern ) {
$target =~ $pattern; # or $target =~ m/$pattern/
}
嗯,验证正则表达式需要了解您期望的输入类型。正则表达式运算符与自动机接受的字符串集之间存在直接关系。
这里的问题是通常字符串集不是众所周知的或者指定的不正确,例如:
正则表达式中的基本运算符集是基本语言字符集(提供要操作的符号)和使事情变得复杂的运算符:这是替代方案 |
(select一个或另一个),连接(没有符号,因为两个正则表达式只是放在一起表示一组字符串来自一组,然后是一个字符串,这次来自第二组)和关闭,用 *
表示(这最后的意思是允许任何重复 --- 包括 none--- 来自前一组的字符串)。
绝对所有的正则表达式都可以作为一个(主要是更复杂的)表达式来处理,它只使用这三个运算符,仅此而已。例如,可以通过重复应用它的正则表达式来处理 +
运算符,并将 *
添加到第二个实例(用括号括起来以将其全部分组) ?
可选后缀可以通过以下规则处理 (regexp)? == (regexp|)
(使用或不使用它的替代方法)
-
|
表示另一种选择...您提供两组字符串,结果集是两组的并集。这意味着如果一个字符串属于一个或任何一个集合,它将被接受。 - 连接表示集合是通过评估两个集合的笛卡尔积来构建的。你需要做成对的字符串,从第一组中取出一个,从另一组中取出第二个,所有可能的组都是这样形成的。
- 闭包意味着将字符串构建为来自同一集合的一系列(可能为零)实例....这意味着您可以连接该集合中的任何实例。
这组规则将为您提供构成正则表达式的完整字符串集。这可以与您的想法一致(或不一致)...但是如果您的想法定义不明确,那么它将是您的正则表达式。
因此,作为结论,您要求一个通用程序来测试您自己的想法以及您如何设计正则表达式。有一个定理(称为 Pumping 定理)用于证明正则表达式和有限状态自动机的等价性。这是一项非常重要的成就,因为它允许您使用正则表达式进行高效的单次传递、字符串识别。如果深入研究这一点,您会发现可以编写一个工具,该工具可以从正则表达式系统地构建将被某些正则表达式接受的完整字符串集。不过这有一个问题,就是许多正则表达式会创建无限组字符串,这意味着该算法不会在有限时间内完成。
作为最后的评论,我可以告诉您,这使正则表达式成为 select 字符串的一个非常强大的工具。您可以使用正则表达式检测复杂的事情,例如,作为一串数字,该数字构成十进制形式的 23 的倍数,或者验证信用卡号码是否存在转录错误。
如果您需要对提供给您的内容保持完全的偏执,您可以使用 Safe 模块来限制可用于 eval()
上下文的操作码。
您可以根据自己的需要在 permit_only()
中添加或减去。
sub safestringeval ($) {
require Safe;
my $safe = Safe->new;
$safe->permit_only(qw/:base_core anonhash anonlist gvsv gv gelem padsv padav padhv padany/);
return $safe->reval($_[0], 1);
}
$regex = safestringeval('qr{'.$input.'}');
我真的不记得这个的用例所以我查了一下。 :) 允许输入的字符串包含实时转义序列。