【问题标题】:Regular expression for regular expressions? [duplicate]正则表达式的正则表达式? [复制]
【发布时间】:2014-03-17 03:09:51
【问题描述】:

可能重复:
Is there a regular expression to detect a valid regular expression?
Regular expression for finding a regular expression?

我有一个允许用户输入正则表达式的应用程序。如何检查正则表达式的任何输入并确保它们是有效的,因为如果它们不存在就会出现 preg_match 错误?

我不想在 preg_match 之前使用“@”,所以如果有办法检查用户输入的正则表达式的有效性,那就太好了。

PHP的正则表达式系统似乎太复杂了,我无法为他们想出一个正则表达式。

【问题讨论】:

  • 根据应用程序的目的,您可能希望以某种方式为此设置超时。用户可以很容易地有意或无意地输入一个正则表达式,该正则表达式会灾难性地回溯并在此过程中使用大量服务器资源。

标签: php regex


【解决方案1】:

在数学上,使用正则表达式验证正则表达式是不可能的。这是因为(正式的)正则表达式只能识别常规语言。语言是字符串的任何。例如,所有十进制数的集合是一种语言(顺便说一句,可以使用正则表达式来描述);所有有效正则表达式的集合也是一种语言。 常规语言是只需要固定有限内存(不是输入大小的函数)即可被识别的语言。

包含所有有效正则表达式的语言不是正则语言;因此使用正则表达式是不可能识别正则表达式的。

要理解这一点,请注意正则表达式中包含必须匹配的括号。因此,如果发生了“(”,则稍后必须发生“)”。这是不可能用只有固定有限内存的机器来描述的。因为,如果有 一种方法可以做到这一点,并且您的正则表达式具有 K 个不同状态的有限记忆(对于某个整数 K),则带有 K 个左括号的表达式后面是 K 个右括号,尽管有效的正则表达式可能无法被该机器识别——一个矛盾(请注意,在正式语言中,我们的假设是文本处理一次发生一个字符,从左到右,这与应用的正则表达式相同)。我们称诸如描述正则表达式的语言为 context-free 而不是 regular

(使用Pumping Lemma证明正则表达式不形成正则语言是微不足道的)

因此,使用正则表达式识别正则表达式存在一个基本的计算机科学问题:数学上不可能做到。

有限状态自动机可以识别常规语言,即具有有限状态但没有记忆的机器。为了解决您的问题,您需要添加一些取决于输入大小的内存。正则表达式,因为它们是上下文无关的(幸运的是它们不是一些晦涩难懂的语言类型),可以使用 下推 自动机在线性时间内识别。这是一个“for”循环,一次通过表达式一个标记(通常是一个字符)并跟踪它在 stack 上看到的内容,即它“推送”它稍后的数据“ pops”以先进后出的方式。 (推送到堆栈的数据示例:“我需要记住稍后找到匹配的 `)'!”;您可以根据需要多次“推动”它;你可以稍后“弹出”它,当你需要检查你是否真的需要之前匹配了一个左括号)。

当然,为正则表达式编写自己的识别引擎会有点开销——但如果你想这样做,你应该知道上面的限制。使用已经存在的机制来做这件事会更明智——我怀疑你可以把这项工作交给正则表达式库或更热衷于处理正则表达式的语言,如 Perl;但是@-method 听起来并不是一个坏主意:它可能很慢,但是您的用户可能会输入非常慢的正则表达式;这可能是一种不好的做法,但在您的情况下,这似乎是可用的最佳解决方案。

维基百科的一些相关文章:

我希望这会有所帮助!

【讨论】:

  • +1:答案很长,但这是唯一正确的答案。 PCRE 中的正则表达式语法是一种上下文无关的语言。另外:考虑将您的文章引用链接到维基百科本身:-)(抱歉,如果我错过了您已经在执行此操作的忍者编辑)
  • 感谢您的建议!我在“实现和运行时间”部分下的“正则表达式”文章中添加了一小段,参考了这篇文章:)
  • 正则表达式描述的语言不一定是正则的(至少如果我们谈论的是现实世界的正则表达式,而不是数学结构);具体来说,PCRE 中的反向引用可用于描述不规则语言,如 a^n b^m a^n。一些 PCRE 风格允许递归、条件子模式、原子组等。此外,PCRE 不是上下文无关语言,因为命名子组不能重用名称。
  • Tgr:这正是我说“正式的正则表达式”的原因。要正式学习 PCRE,就必须为它构建一种正式的语言——如果你问我,那就太麻烦了。无论如何,PCRE 是最好的上下文无关的(如果我们选择只使用它的一些常见方面),所以它肯定不能使用具有固定大小内存的有限状态自动机进行解析,结果仍然成立:正则表达式无法使用正则表达式进行验证。
【解决方案2】:

preg_match() 在发生错误时返回FALSE

  1. 将表达式发送到服务器
  2. preg_match 在一个空字符串上
  3. 查看是否出现错误

您可以使用 Ajax 进行实时验证,也可以在表单提交后进行验证。
您也可以尝试通过将表达式提供给 javascript regexp 引擎来进行验证,但是 js regexp 语法不是 100% 与 php 兼容。

【讨论】:

  • 确保使用类型安全的比较:preg_match(…) === false
  • 澄清一下:这正确回答了“是否有方法来检测有效的正则表达式?”。如果你想要一个正则表达式,就像@dionyziz 解释的那样是不可能的。
【解决方案3】:

让用户提交正则表达式几乎可以肯定是个坏主意。

有些表达式非常昂贵。试试这个:

preg_match('/(.*){1,32000}[bc]/','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')

这只是 30 个字符的输入!它们也不全都这样:/^(?:(\d+)|::)*$/ 在 PCRE 中也是指数时间。

【讨论】:

    【解决方案4】:

    想到的第一个方法是在调用preg_match($sanatized_user_regex, ""); 之后使用preg_last_error() 如果您收到PREG_NO_ERROR 以外的任何内容,则使用相应的错误消息进行响应。

    【讨论】:

      【解决方案5】:

      你的问题有点模棱两可。您是要验证正则表达式的“语法”,还是要确保正则表达式在应用于字符串后实际解析出内容。我认为在任何一种情况下,您都应该将验证留给用户(例如,提供一个调试/文本框,他们可以输入一个字符串来匹配他们的正则表达式。如果正则表达式有问题或者找不到匹配项,请显示“未找到”错误)。

      就验证正则表达式本身而言,您可能希望从一个简单的验证器开始,该验证器检查只有有效字符(例如,正则表达式语法的一部分,如 $、^ \t 等)是其正则表达式的一部分,但我认为尝试验证正则表达式中的逻辑结构可能相当复杂。也许有一些库可以验证正则表达式语法,但我不知道。

      【讨论】:

        猜你喜欢
        • 2018-03-21
        • 2015-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多