如何在用户输入中验证 Perl 正则表达式?



我从用户那里得到了一个据称有效的perl正则表达式值的输入列表。 示例可以是:

  • b[Bb]ananab
  • s*Apples[BANANA]s+

有没有一种安全的方法来验证这些字符串?

首先,考虑您希望让用户对模式执行多少操作。Perl 正则表达式可以运行任意代码。

但是,若要验证是否可以将字符串用作模式而不会导致致命错误,可以使用qr//运算符编译字符串并返回正则表达式。如果出现问题,qr会给您一个致命的错误,您可以使用eval捕获该错误:

my $pattern = eval { qr/$input/ };

如果您返回undef,则该模式无效。而且,尽管问题中有评论,但有无数种方法可以制作无效模式。我知道,因为我一直在手动输入它们,而且我没有用尽办法搞砸:)

这不会将模式应用于字符串,但您可以使用$pattern进行匹配:

if( $pattern ) {
$target =~ $pattern;  # or $target =~ m/$pattern/
}

如果您需要对提供给您的内容完全偏执,则可以使用 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.'}');

我实际上不记得这个用例,所以我查了一下。 :)这是为了允许输入的字符串包含实时转义序列。

好吧,验证正则表达式需要了解您期望的输入类型。 正则表达式运算符与自动机接受的字符串集之间存在直接关系。

这里的问题是,通常字符串集并不为人所知或指定不当,例如:

正则表达式中的基本运算符集是基本语言字符集(提供要操作的符号)和使事情变得复杂的运算符:这是替代|(选择一个或另一个),连接(没有符号,因为两个正则表达式只是放在一起表示来自一组的字符串集, 然后是一个字符串,这次来自第二组)和闭包,由*符号表示(最后一个含义允许任何重复---包括没有---来自前一组的字符串)。

绝对所有的正则表达式都可以作为一个(大多数情况下,更复杂的)表达式来处理,它只使用这三个运算符,而不是更多。 例如,可以通过重复应用+运算符的正则表达式来处理,并将*添加到第二个实例(用括号括起来以将其全部分组)?可选后缀可以通过以下规则处理(regexp)? == (regexp|)(是否使用它的替代方案)

  • |意味着另一种选择...您提供两组字符串,结果集是两个集合的并集。 这意味着如果字符串属于一个或任何集合,则将接受该字符串。
  • 串联意味着集合是通过评估两个集合的笛卡尔乘积来构造的。 你需要制作成对的字符串,从第一组取一个,从另一组取第二根,所有可能的集合都是这样形成的。
  • 闭包意味着将字符串构建为来自同一集合的(可能为零个)实例序列。这意味着您可以连接应用集合中的任何实例。

这组规则将为您提供构成正则表达式的完整字符串集。 这可能与您想到的重合(或不重合)重合......但是,如果您的想法定义不明确,那么它将是您的正则表达式。

因此,作为结论,您要求一个通用程序来测试您自己的思维以及如何设计正则表达式。 有一个定理(称为抽水定理)用于演示正则表达式和有限状态自动机的等价性。 这是一个非常重要的成就,因为它允许您使用正则表达式进行高效的单次传递、字符串识别。 如果你深入研究这一点,你会发现可以编写一个工具,从正则表达式可以系统地构建将被某些正则表达式接受的完整字符串集。这有一个问题,即其中许多正则表达式创建了无限的字符串集,这意味着算法不会在有限的时间内完成。

作为最后的评论,我可以告诉你,这使得正则表达式成为选择字符串的非常强大的工具。 例如,您可以使用正则表达式检测复杂的东西,例如,一串数字使数字以十进制形式成为 23 的倍数,或者验证信用卡号码是否存在转录错误。

最新更新