什么时候不应该使用正则表达式?[关闭]


50

正则表达式是程序员的强大工具,但是-在某些情况下,它们不是最佳选择,甚至是完全有害的。

简单的示例1是使用regexp解析HTML-已知的众多错误之路。通常,这也可能归因于解析

但是,还有其他显然不能使用正则表达式的区域吗?


ps:“ 您要提出的问题似乎是主观的,很可能已经解决。 ”-因此,我想强调一点,就是我对使用正则表达式会导致问题的示例感兴趣。


9
使用regexp解析HTML不仅是“已知的众多错误之路”。实际上是不可能的
克拉莫伊(Kramii)恢复莫妮卡(Monica)

19
这不仅是不可能的,而且还会导致疯狂和永恒的诅咒
Martin Wickman

3
@Jörg:Regexp只是正则表达式的缩写。
Joren

3
@Jörg:的确,数学中的正则表达式与软件库中的实现之间存在巨大差异。的确,大多数正则表达式库都具有扩展名,这些扩展使它们远远超出了仅接受正则语言的范围,并且称它们为正则表达式并不总是那么合适。我同意你的看法,有两个不同的概念。但是他们有相同的名字。regexp仍然只是缩写,而不是术语本身。该站点上的大量示例都使用了完整的软件库术语。
Joren

2
@Jörg-这些是语义。虽然最好用不同的名称来称呼这些模式(如果只是避免“正则表达式用于正则语言”的谬误),但是“ regexp” /“正则表达式”并不是一个很好的尝试,只会导致额外的混乱。
科比

Answers:


60

不要使用正则表达式:

  • 有解析器时。

这不限于HTML。即使知道模式并且知道它永远不会改变,也不能使用正则表达式合理地解析简单的有效XML。

例如,不要尝试解析C#源代码。相反,解析它以获得有意义的树结构或令牌。

  • 一般来说,当您拥有更好的工具来完成工作时。

如果必须搜索大小写的字母怎么办?如果您喜欢正则表达式,则可以使用它们。但是使用两个搜索,一个接一个地搜索是否更容易/更快/更容易阅读?在大多数语言中,您都有可能获得更好的性能,并使代码更具可读性。

例如,当您不能使用正则表达式时,Ingo答案中的示例代码就是一个很好的例子。只是搜索foo,然后搜索bar

  • 解析人类文字时。

淫秽过滤器就是一个很好的例子。通常,实现它不仅是一个坏主意,而且您可能会想使用正则表达式来实现它,但是这样做会出错。一个人可以通过多种方式写一个单词,一个数字,一个句子,并且另一个人可以理解它,但是您的正则表达式却不行。因此,您的正则表达式不会花费很多时间来伤害其他用户,而不是使您感到淫秽。

  • 验证某些类型的数据时。

例如,不要通过正则表达式来验证电子邮件地址。在大多数情况下,您会做错事情。在极少数情况下,您会做对并以6 343个字符长的编码恐怖结束

没有正确的工具,您会犯错误。您会在最后一刻注意到它们,或者可能永远不会注意到它们。如果您不关心干净的代码,则将编写二十行的字符串,其中不包含注释,空格和换行符。

  • 何时读取您的代码。然后每次都由不同的开发人员一次又一次地阅读。

认真地说,如果我接受您的代码并必须对其进行检查或修改,那么我不想花一个星期的时间来理解长达20行的字符串,其中包含许多符号。


9
“严重的是,如果我接受了您的代码并必须对其进行审查或修改,那么我不想花一个星期的时间来理解二十行长的字符串,其中包含许多符号。” +1!
funkybro 2011年

1
这是一个比其堆栈溢出问题的姊妹更好的答案:stackoverflow.com/questions/7553722/…–
Kobi

1
如果您使用的是Perl / PCRE(可能还有其他现代的regex风格),请阅读有关子例程,名为捕获组和(?(DEFINE))断言的;)您可以使用它们编写非常干净的regexe,实际上,当您使用它们时,您将编写语法非常类似于您用yacc等编写的内容;)
NikiC 2011年

2
使用正则表达式解析掉列入黑名单的单词是一个错误提示。
丹·雷

世界上没有理由避免在像这样的字符串上抛出正则表达式"<a href='foo'>stuff</a>"。现代正则表达式对此没有任何问题。
tchrist 2012年

18

最重要的是:当您解析的语言不是常规语言时

HTML是不是一个正规的语言,并用正则表达式解析它是没有可能的(不仅难以或道路bug的代码)。


4
错误!如果您使用任何现代的正则表达式类型(Perl,PCRE,Java,.NET等),您都可以进行递归和断言,因此还可以解析与上下文无关和上下文敏感的语法。
NikiC 2011年

9
@NikiC。没有错。“现代正则表达式样式”不是正则表达式(可用于解析正则语言,因此是名称)。我同意使用PRE可以做更多的事情,但是我不会称它们为“正则表达式”(就像在原始问题中一样)。
Matteo,

1
现代正则表达式远远超出了您祖母所教的范围,正则表达式可以做到这一点,但她的建议并不重要。甚至原始正则表达式也可以处理大多数HTML片段。这种全面禁止是荒谬的和不现实的。正则表达式中提出了这样的事情。是的,我确实知道我在说什么
tchrist 2012年

12

在stackoverflow上经常会看到人们要求使用正则表达式来查找给定的字符串是否包含该字符串。恕我直言,这颠倒了正则表达式的目的。即使存在解决方案(采用断言在后面的断言或类似的东西),通常也最好使用正则表达式进行处理,并使用程序逻辑处理否定情况。

例:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}

1
+1:有几次,我通过停止并问自己“好吧,我到底想匹配什么?”来避免自己用正则表达式编码。而不是“我想避免什么?”

5

两种情况:

有更简单的方法

  • 大多数语言都提供了一个简单的函数,如INSTR,来确定一个字符串是否是另一个字符串的子集。如果您要这样做,请使用更简单的功能。不要写自己的正则表达式。

  • 如果有一个库可以执行复杂的字符串操作,请使用它,而不要编写您自己的正则表达式。

当正则表达式不够强大时

  • 如果需要解析器,请使用解析器。

0

正则表达式无法识别递归结构。这是基本限制。

以JSON-这是一种非常简单的格式,但是由于一个对象可能包含其他对象作为成员值(任意深),因此语法是递归的,并且不能由正则表达式解析。另一方面,由于CSV 不包含任何递归结构,因此可以通过正则表达式进行解析。

简而言之,正则表达式不允许模式引用自身。您不能说:此时语法再次匹配整个模式。换句话说,正则表达式仅线性匹配,它不包含堆栈,因此它无法跟踪嵌套模式的深度。

请注意,它与格式的复杂程度或复杂程度无关。S表达式确实非常简单,但是不能用正则表达式解析。另一方面,CSS2是一种相当复杂的语言,但是不包含递归结构,因此可以使用正则表达式进行解析。(尽管由于CSS表达式具有递归语法,所以CSS3并非如此。)

这样做不是因为仅使用正则表达式来解析HTML是丑陋,复杂或容易出错的。这是根本不可能的

如果您需要解析包含递归结构的格式,则至少需要使用正则表达式来补充堆栈,以跟踪递归结构的级别。这通常是解析器的工作方式。正则表达式用于识别“线性”部分,而正则表达式外的自定义代码用于跟踪嵌套结构。

通常,像这样进行解析会分为多个阶段。令牌化是使用正则表达式将输入拆分为一系列“令牌”(如单词,标点,方括号等)的第一阶段。解析是下一阶段,其中将这些令牌解析为层次结构(语法树)。

因此,当您听到HTML或C#无法由正则表达式解析时,请注意,正则表达式仍然是解析器的关键部分。您只是不能使用正则表达式而不使用辅助代码来解析此类语言。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.