正则表达式与字符串解析比较

49

冒着引发争议和负面反应的风险,我发现自己需要问:

 

何时应该使用正则表达式,何时更适合使用字符串解析?

我需要实例理由来支持你的观点。我希望你能谈一谈答案中的可读性可维护性可伸缩性,可能最重要的是性能等问题。

我在这里找到了另一个问题,只有一个回答者提供了示例。 我需要更多的例子来理解它。

我目前在用C ++玩耍,但几乎每种高级语言都包含正则表达式,我想知道不同语言如何使用/处理正则表达式,但这只是一个想法。

感谢帮助我理解它!

编辑:我仍然在寻找更多示例和讨论,但迄今为止的回复已经很好了。:)


2个回答

42

这取决于你所处理的语言的复杂程度。

分割

当没有转义约定时,这种方法非常有效。但是对于 CSV 等格式来说并不适用,因为引号内的逗号不是正确的分割点。

foo,bar,baz

将被正确分割,但是

foo,"bar,baz"

则不会。

正则表达式

正则表达式非常适合具有 "正则文法" 的简单语言。Perl 5 正则表达式由于支持反向引用而更加强大,但是一般的经验法则是:

如果你需要匹配括号((...)[...])或其他嵌套结构,例如 HTML 标签,则仅使用正则表达式是不够的。

你可以使用正则表达式将字符串分成一个已知数量的块,例如从日期中提取月/日/年。但是它们不适用于解析复杂的算术表达式。

显然,如果你写了一个正则表达式,离开一会儿喝杯咖啡回来,却无法轻松理解你刚才写的是什么,那么你应该寻找一种更清晰的方式来表达你正在做的事情。 电子邮件地址 可能已经达到了使用正则表达式正确且可读地处理的限度。

上下文无关

解析器生成器和手工编码的推入/PEG解析器非常适合处理更复杂的输入,其中需要处理嵌套,以便可以构建一个树形结构或处理 运算符优先级或关联性。

上下文无关解析器通常首先使用正则表达式将输入分成块(空格、标识符、标点符号、引用字符串),然后使用语法将这些块的流转换为树形结构。

CF语法的经验法则是

如果正则表达式不足够,但是语言中所有单词的意义都不受先前声明的影响,则可以使用CF。

非上下文无关

如果您的语言中的单词在不同的上下文环境中具有不同的含义,那么您需要一个更为复杂的解决方案。这些解决方案几乎总是手动编码的。例如,在C语言中,
#ifdef X
  typedef int foo
#endif

foo * bar

如果 foo 是一种类型,那么 foo * bar 就是一个名为 barfoo 指针的声明。否则它就是一个名为 foobar 的变量相乘。

4
@Dan,正则表达式可以很好地处理CSV文件——没有任意深度的嵌套,只有两层深度的结构。对于IE样式,您可以使用类似于/([^\r\n"]|"(?:[^"]|"")*")/g这样的表达式来查找行,该表达式允许在用一对双引号转义双引号的引号字符串内部包含换行符。然后,您可以使用类似于/([^,"]|"(?:[^"]|"")*")*/g这样的表达式来查找行中的字段。然后,您只需要使用/"(?:[^"]|"")*"/查找带引号的部分,去掉外部引号并将所有出现的 "" 替换为 `"”。 - Mike Samuel
1
@MikeSamuel - “电子邮件地址可能是使用正则表达式正确且可读性最高的极限。” 这是荒谬的。 正则表达式确实是一种独立的语言,需要深入理解,但这并不意味着我们应该编写大量的过程代码来解析字符串,因为我们只是不理解。 知道如何使用正则表达式可以极大地提高任何代码的可维护性和可读性。 正则表达式很复杂,但非常标准化。 过程解析代码容易出错且费力。 - Joey Carson
@JoeyCarson,你似乎想反驳你引用的那一点。我断言:(1)正则表达式和过程代码之间不存在二分法,(2)我从未声称不需要了解正则表达式,引用的文本也没有暗示这一点,(3)熟练掌握正则表达式语法并不能帮助我们轻松地处理电子邮件 -- http://emailregex.com/ 既不小巧简单,也不易读。如果你认为正则表达式比 CF 语法和代码更适合处理电子邮件,请提供证据。指向网络邮件系统中正则表达式的指针会很好。 - Mike Samuel
在某些语言中,您可以应用递归正则表达式,您可以使用它来完成括号操作...我曾经从字符串构建正则表达式,因此我可以将其拆分并使用变量名称解释每个部分。 - inf3rno
我同意@JoeyCarson的观点,你没有给正则表达式足够的信任。另一个常见的错误是使用单个复杂的“大模式”,而不是多个简单的模式。功能编程者也有类似的趋势,他们试图在一行代码中解决所有问题,并惊讶地发现结果难以阅读。 - inf3rno
显示剩余3条评论

11

应该是正则表达式和字符串解析

你可以充分利用它们!许多程序员试图使用一个单一的正则表达式来解析文本,然后发现很难维护。你应该根据需要使用它们。

正则表达式引擎非常快速。简单的匹配只需要少于一微秒的时间。但不建议用于解析HTML。


3
“当需要时,你应该同时使用两者。” 什么时候?我需要一个例子。我的意思是,你的话有道理,但我需要解释一下你确切的意思。 - Dan
2
@Dan,看一下我的答案,这是一个常见的情况。在解析CF语言时,通常会使用正则表达式将其拆分为标记,然后使用完整的解析器处理标记流。例如,您可以将"(a + b)*c"拆分为["(", " ", "a", "+", " ", "b", ")", "*", "c"],然后丢弃空格并将结果传递给解析器来处理括号和运算符优先级,从而生成像(Times (Plus (Var "a") (Var "b")) (Var "c"))这样的树形结构。 - Mike Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接