代码之家  ›  专栏  ›  技术社区  ›  Null303

什么时候问题对于正则表达式来说过于复杂?

  •  20
  • Null303  · 技术社区  · 17 年前

    请不要回答显而易见的问题,但哪些极限符号告诉我们不应该使用正则表达式解决问题?

    例如:为什么完整的电子邮件验证对于正则表达式来说太复杂了?

    13 回复  |  直到 11 年前
        1
  •  14
  •   Daniel Spiewak    17 年前

    正则表达式是 finite-state automata . 也就是说,它们仅限于非递归匹配。这意味着在regexp中不能有任何“范围”或“子匹配”的概念。考虑以下问题:

    (())()
    

    所有的开放式排列与封闭式排列匹配吗?

    很明显,当我们把它看作人类时,我们很容易看到答案是“是的”。但是,没有正则表达式能够可靠地回答这个问题。为了进行这种处理,您需要一个完整的 pushdown automaton (类似于带有堆栈的DFA)。这通常以解析器的形式出现,例如由ANTLR或Bison生成的解析器。

        2
  •  13
  •   Jeff Atwood    17 年前

    1. 开始和结束标记检测——匹配配对
    2. 递归
    3. 需要向后走(虽然可以反转字符串,但这是一种技巧)

    正则表达式,尽管我很喜欢它们,但不擅长这三件事。记住, 保持简单! 如果您试图构建一个“无所不能”的正则表达式,那么 you're probably doing it wrong .

        3
  •  9
  •   Adam Rosenfield    17 年前

    当您需要解析未由 regular language .

        4
  •  7
  •   Community Mohan Dere    5 年前

    归结起来就是运用常识。如果您试图匹配的内容变成了一个不可管理的怪物正则表达式,那么您需要将其分解为小的逻辑次正则表达式,或者需要重新思考您的解决方案。

    \b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b
    

    它短小精悍,你很少会遇到问题。然而,正如RegEx buddy的作者所指出的,如果您的电子邮件地址位于罕见的顶级域名“.museum”中,则不会被接受。

    要真正匹配所有电子邮件地址,您需要遵守称为 RFC 2822 . 它概述了电子邮件地址格式化的多种方式,而且非常复杂。

    (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"
    (?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x
    0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]
    (?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.)
    {3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08
    \x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
    

    正则表达式是程序员工具箱中的一个很好的工具,但它们并不能解决所有解析问题。如果您发现您的正则表达式解决方案开始变得极其复杂,您需要尝试将其逻辑分解为更小的正则表达式以匹配文本的部分,或者您需要开始寻找其他方法来解决您的问题。类似地,由于正则表达式的性质,它们无法解决一些简单的问题(正如一位海报所说,不遵守规则) Regular Language ).

        5
  •  6
  •   Jan Goyvaerts    17 年前

    正则表达式适用于标记化、查找或标识文本的各个位,例如在源代码中查找关键字、字符串、注释等。

    正则表达式不适合确定多个文本位之间的关系,例如,查找具有正确大括号对的源代码块。你需要一个解析器。解析器可以使用正则表达式对输入进行标记化,而解析器本身确定不同的正则表达式如何匹配在一起。

    从本质上讲,如果您开始考虑“平衡组”(.NET的捕获组减法功能)或“递归”(Perl 5.10和PCRE),那么您的正则表达式将走得更远。

        6
  •  4
  •   Niniki    17 年前

    下面是陈雷蒙的一句话:

    不要让正则表达式做它们不擅长的事情。如果要匹配一个简单模式,请匹配一个简单模式。如果你想做数学,那就做数学。正如评论员毛里茨所说,“诀窍不是花时间开发一个组合锤子/螺丝刀,而是使用锤子和螺丝刀。

    Source

        7
  •  3
  •   Coderer    17 年前

    用正则表达式解决问题,然后把它交给其他熟悉正则表达式的人。如果他们不能在大约10分钟内告诉你它是做什么的(或者至少自信地说他们理解),那就太复杂了。

        8
  •  3
  •   ADEpt    17 年前

    停止使用regexp的确定标志是:如果您有许多分组大括号“()”和许多可选项“|”,那么您尝试执行(复杂)操作的确定标志 使用正则表达式。

    添加到混合Perl扩展、反向引用等中,很快您就拥有了一个难以阅读、难以修改和难以解释其属性的解析器(例如,是否有一个输入,该解析器将在指数时间内工作)。

    这是停止regexing并开始解析(使用手工解析器、解析器生成器或解析器组合器)的时候了。

        9
  •  2
  •   Community Mohan Dere    9 年前

    除了大量的表达式外,单词还有一些主要的限制,这些限制可以由regexp处理。 例如,您不能为n个字符a和n个字符b描述的单词编写regexp,其中n可以是任意字符,更严格地说 alt text .

    在不同的语言中,regexp是 Regular language ,但解析时间可能非常长,并且此代码不可移植。

        10
  •  1
  •   Vinko Vrsalovic    17 年前

    当您不能确定它是否真的解决了问题时,例如:

    • 电子邮件验证

    尤其是当已经存在以完全可以理解的方式解决问题的工具时。

    Regex可以在我提到的领域中使用,但只能作为整个问题的子集,用于特定的简单情况。

        11
  •  0
  •   BoltBait    17 年前

    当问题的约束在编写解决方案后可能发生变化时,问题对于正则表达式来说过于复杂。因此,在您的示例中,当您无法访问目标邮件系统以验证电子邮件地址是否附加到有效用户时,如何确保电子邮件地址有效?你不能。

        12
  •  -1
  •   James Curran    17 年前

    我的限制是大约30-50个字符长的正则表达式模式(取决于固定文本和正则表达式命令的长度)

        13
  •  -1
  •   Miserable Variable    17 年前

    +complex AND +"regular expression"

    例如,如何在emacs中搜索名称中同时包含Buffer和Window的命令?我需要单独搜索 .*Buffer.*Window and .*Window.*Buffer