为什么正则表达式如此令人着迷?


23

图表1图表2,我想您会很难回想起其他示例。

问题是:如果有多种方法可以解决问题,PHP程序员(我通常在StackOverflow上浏览PHP标记)将寻求有关正则表达式的解决方案的帮助。

即使经济性较差,当不需要花哨的替换规则时,即使 php手册建议(linkstr_replace代替任何preg_*ereg_*函数使用,也是如此。

有人知道为什么会这样吗?

别误会我的意思,我最好的朋友中有一些是正则表达式,我也不鄙视Perl。我没有得到的是为什么即使在过度杀伤很明显(正则表达式切换字符串)或代码复杂性呈指数增长(正则表达式用于从PHP中的 html获取数据)的情况下,也没有寻找替代方法的原因


2
您可能想引用php手册的实际含义。
克里斯·弗雷德

1
因为它们是神秘的,所以您想成为独家kewl kidz'俱乐部的成员吗?主要是因为它们提供了表达匹配或提取的简短方法,这正是它们的目的。当然可以处理假的情况,如果更好的话可以进行自定义解析,但是开发快速正则表达式的开发时间更倾向于正则表达式。
haylem 2012年

您强调了最后一句的错误部分:它的离谱部分是“ from html”,而不是“ in PHP”。
Izkata 2012年

Answers:


20

为什么正则表达式如此令人着迷?

因为在潜意识层面上,他们感觉像是一个完整的智能程序,可以在包含和自我调整(思考模式)的同时独立完成很多工作。

这就是为什么人们立即相信正则表达式可以解决他们所有基于文本的任务,以某种方式不认为它可能是过大的,而没有意识到这可能是我的不足(使用语言进行解析)。

包含魔力的小东西。你不能说不,可以吗?


5
+ 1-一件神秘的小事,不少。
AJ Johnson

习惯很棘手
Ben DeMott

49

当您拥有的唯一工具是正则表达式时,每个问题看起来像 ^((?>[a-zA-Z\d!#$%&'*+\-/=?^_{|}~]+\x20*|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$


16
选择这个答案的诱惑是如此强烈,但是我想我必须抵制,因为这是我的第一个问题,我必须假装认真一会儿。
cbrandolino

1
@Dev,这很有意义。我的评论只是一种表达我对答案的赞赏的有趣方式。
cbrandolino

17
这个匹配到底是什么?
汤姆·奥康纳

4
我不知道...我认为这几乎可以总结整个过程。如果您了解正则表达式,但不了解其他方法,那么为什么要继续寻找呢?您已经有了一个工具,如果正确完成,它将可以处理这项工作。直到他们偶然碰到更简单的方法或被告知之前,即使正则表达式比需要的复杂,它也将是万能的方法。
Aeo 2010年

4
@Tom O'Connor我认为它与用于匹配RFC 2822电子邮件地址的正则表达式很接近,但是我不得不删除几个字符,因为它们对降价造成了严重破坏。
glenatron 2010年

23

我认为是因为:

  1. 与等效代码相比,它们简明扼要(正确使用时),并且
  2. 它们在各种编程语言中得到了广泛的支持,因此大多数开发人员都对它们很熟悉。

3
#2很有道理。
cbrandolino

23

在我职业生涯的早期阶段(即PHP之前的时代),我是Perl专家,Perl专家的一个主要方面是精通正则表达式。

在我目前的团队中,从字面上看,我是唯一一位在其他(通常是更糟糕的)工具之前使用正则表达式的人。在团队的其他成员看来,他们是纯魔术。他们将溜到我的办公桌前,要求一个正则表达式,实际上花了我10秒钟才把它们放在一起,然后在工作时被炸掉。我不知道-我已经与他们合作了很长时间,这很自然。

在缺少正则表达式流畅性的情况下,您会留下流控制语句的组合,这些流控制语句包装了strstr和strpos语句,这些语句丑陋且难以运行。我宁愿制作一个优雅的正则表达式,也不愿编写三十行的字符串搜索。


2
我不能对此表示足够的赞同。
CaffGeek

8
我很好奇:您阅读 regexp的程度与编写它们时一样流利吗?
peterchen 2010年

7
希望您能定期进行正则表达式培训课程和/或从代码中记录地狱;否则,您将为同事制造支持噩梦。试图理解“优雅正则表达式”所做的事情的人可能会浪费一百倍的时间来编写正则表达式。
杰夫·克内希特

3
很好。您可以在这些评论中听到爱与恨正则表达式之间的拉锯战。
丹·雷

1
@Ben Lee:我想是这样-OTOH,我从未在野外遇到过评论过的正则表达式。正则表达式的一些问题可能基于冷静的态度。
peterchen

16

反之。人们经常在IMO 上欺骗正则表达式是邪恶的模因。显然preg_match在中已被过度使用php,但是这样做并不明显(在PHP中)通常是明智的。

我可能会猜到这是使用字符串函数在php领域进行的另一个微优化。有很多有用的东西,它们通常是更好的选择。但是,您不应避开preg_match多重strposif连锁。因为事实证明,libpcre通常比PHP执行循环查找字符串替代品的速度更快,例如

最近的一个例子让我意识到,测试字符串是否全部为小写:

 if ($string == strtolower($string))

比以下内容更具可读性:

 if (!preg_match("/[A-Z]/", $string))

而且您会认为第一个必须更快,因为它是全PHP。但实际上,正则表达式只对字符串进行一次查找,并且一旦发现大写字母就可以中止取反的条件。但是,strtolower()方法对字符串进行了两次查看。首先strtolower()通过遍历每个字母,比较并大写字母,使字符串重复。然后==再次遍历原件和副本,再次比较它们。

因此,这不是一个明显的情况。客观地说,第一个通常会更快,因为您通常只比较短字符串。但是当务之急是不要盲目假设PHP字符串函数始终建议使用正则表达式。

(我很想对@bobince关于xhtml-regexes 的有趣答案以及最近如何经常以一种非常无益的方式链接它添加另一种怨言。下面更客观的答案被忽略了。)


1
我同意你的榜样;不过,在这种情况下,无论如何,我还是更喜欢“ strtolower()”:在非关键代码中,即使是这么大的(相对于其他实现而言)执行时间优化也是微不足道的-除非您要评估小写字母-文本文件的功能,但我无法想象会有什么用处。
cbrandolino

1
@cbrandolino:那里没有讨论。这种东西应该只能每个具有相关性和评估嵌套循环,它可能使一个事实的差异。
mario 2010年

4
+1事实是人们总是对他们ash之以鼻,远远超出了他们的支持范围。
2010年

1
作为“正则表达式打击者”之一:有趣的是,看到一个内衬或多或少地表达了解析nedds 30行的“手动”字符串的含义。但是,在最实际的示例中,维护受到影响。此外,当尝试将它们应用于未经验证的输入时,为拒绝的输入生成合适的诊断信息需要额外的技巧。对我来说,这是典型的“只写”代码-对于快速脚本很酷,对于长期使用的应用程序则很烂。
peterchen

1
任何人如果不/x以某种方式编写所有正则表达式,都不允许在空白处留有认知块,并且需要注释来解释为什么要这样做,那么当然应该把他的耳朵塞满。但是对于具有合理复杂性的真实正则表达式,您需要考虑通过语法正则表达式应用自顶向下的设计。一旦看到光,您将永远不会回到/@#$^^@#$^&&*)@#/
tchrist 2012年

8

正则表达式非常吸引人,因为它们是解析正则语言的最佳工具。

它们具有以下优点:

  • 他们简明扼要。与使用正则表达式相比,使用您想出的特定算法来解析特定的常规语言通常需要花费更多的代码。
  • 它们使用起来很快。与使用regexp相比,使用您想出的特定算法为特定的常规语言编写解析器通常需要更多的时间。
  • 他们很容易。一旦您学习了一组特殊字符及其含义,就很容易编写一个正则表达式(尽管很难读懂它们)。正则表达式本身就是语言,这是一个有用的特征,因为我们的物种已经发展为非常擅长语言。
  • 他们很快。编译后,它们可以匹配NO(N)时间中的字符串长度。
  • 它们很灵活。它们可以匹配任何常规语言,并且我们的许多数据都以常规语言表示。
  • 它们无处不在。大多数编程语言都具有基本的regexp支持-通过外部库或嵌入到语言本身中。regexp语言本身之间也没有太大的差异。

这使它们在适合的情况下具有吸引力,但是人们可能会在不是最佳工具的情况下使用它们,因为它们:

  • 不明白它们匹配的内容不能使用正则表达式(例如HTML)来表达。
  • 懒惰(以一种不好的方式)-他们知道一种工具,并认识到它不是执行工作的最佳工具,但是它可以无问题地工作95%的时间,并且花费95%的精力学习特定的东西解析器或从头开始编写一个。
  • 他们没有意识到存在更好的工具。

嗯,我指的是一些特定的案例,在这些案例中,它们显然不是最佳的处理方法,但仍在使用。我喜欢regex(我的意思是,我发现它们很无聊,没有生气,但是在某些情况下仍然非常有用),并且知道它们的优点。
cbrandolino

我同意其余的内容,但是又快捷又容易?学习曲线是陡峭的:对于初学者来说,很难弄清为什么表达式不起作用,并且每个正则表达式实现似乎至少都有细微的差别,因此oyu必须注意您尝试从中学习的地方。
peterchen 2010年

为什么每个人都将提取一点点HTML与完全将完整的网页完全解析为完整的解析树相混淆?真是愚蠢。相信我,当我在中编辑HTML页面时vi,您敢打赌我会用:%s/foo/bar/gc它。如果对编辑器足够好,那么对脚本也足够。
tchrist 2012年

6

嗯,我只能猜测。也许有人经历过将其30行代码替换为一个20个字符长的正则表达式,因此,在可以使用正则表达式时,使用其他任何东西来代替它们对他们来说都是错误的。


4

它符合某些人的想法。我不喜欢它们,但是我有一些朋友似乎在正则表达式中考虑。我猜想他们大脑的模式匹配部分比正式逻辑部分更容易被暴露。:-)


6
就我们的进化史而言,这是有道理的。我们早在定义语法或发现三段论之前就已经匹配了模式。
glenatron 2010年

1
我不同意,编程涉及逻辑和模式匹配两个领域。正则表达式非常擅长模式匹配,应该用于此类任务。太说“我不喜欢他们”是为了丢掉一份用于特定工作的好工具。
2010年

@Orbling:问题不在于它们是好是坏,而是为什么有些人过度使用它们而其他人却没有。
Lennart Regebro

问题可能是,但您的答案表明一种或另一种思维方式正在发挥作用,而不是同时发挥两种作用。
2010年

我认为“建议”不是正确的词。
Lennart Regebro

3

我认为正则表达式的普遍存在是由于字符串的普遍存在。字符串是最简单的数据结构,也是我们大多数人学习的第一个数据结构。由于我们所有的代码都是以符号形式编写的,因此程序员自然会考虑以符号形式进行建模。但是,如果当我们尝试为巧妙的新符号形式扩展其语法时,我们的编程语言带来了任何阻力,则它们最终都会在引号之间结束。关系数据模型具有SQL。XML数据模型具有XQuery。但是谦虚字符串数据模型呢?正则表达式!

就在昨天,我正在寻找API来寻找支持HTML5游戏开发的新颖的Javascript框架。它具有描述性的机制,用于描述游戏所需的主要子系统。如何指定这些功能?JSON?流利的点符号?数组?Nope-一个字符串,其中包含以逗号和空格分隔的功能名称列表。我不知道它如何解析该列表...?


2

因为您可以一次看到整个事情。通过能够看到整个事情,可以更轻松地进行操作,而且这总是很好。这有点像许多C ++程序员仍然使用printf-type语句的原因:它不是类型安全的(尽管gcc至少可以检查printf语句的类型),并且它不是很漂亮,但是它紧凑且可用。

如果这是一个简单的正则表达式,那么它们通常是做事的最佳方法-紧凑的形式和多种功能使其非常适合某些任务。当您使正则表达式变得如此复杂以至于无法再阅读时,或者当您使用复杂的正则表达式执行可以通过简单的字符串操作更快完成的操作时,就会出现问题。

与其他任何强大的工具一样,正则表达式必须适当地使用-不能太多,也不能太少。并且,除非对性能有很大的关注,否则与多个字符串操作相比,单个正则表达式有时可能会更快地编写并且更容易调试。


2

嗯,当前的答案过于集中在技术方面,以及可读性的优缺点(这重要)。因此,让我尝试将其更多地转移到PHP环境/社区:

  • PHP是Perls的小继父。Perl的组成部分是正则表达式(他们发明了这种东西,不是吗?)。因此,这也是正则表达式在PHP中同样普遍的原因之一。
  • 用例 PHP是巧合没有什么不同使用情况下的正则表达式了。PHP在结构上用于将HTML页面粘合在一起。正则表达式可以处理文本。(WReach说了什么)
  • 微观优化。如前所述:人们在感觉到速度之后经常使用正则表达式和/或PHP字符串函数。PHP圈子中的一个核心问题,不是特定于正则表达式。
  • 正则表达式是内置的。在Python,Java,C#,Ruby中?有可用性,但是阻止了必须加载额外的模块。并了解在PHP或Javascript的核心功能中,使用模式有何不同。另一个展览:CSS越来越多地被使用。
  • PHP手册有过错。通常是这样。正则表达式很容易被发现,我推迟了这个有趣的事实,因为它的明显性很无聊:所有该死的教程和PHP入门书籍都一直在教正则表达式,但是没有对用例进行教育
  • PHP中的字符串API是由为您带来魔术引号和名称空间\分隔符的人设计的。它具有比Java更好的包容性,但整体上没有魅力。特别是如果字符串可以兼作对象(请参阅Python),则字符串函数可能会超过正则表达式。

但这只是旁注。我认为,总的来说,主要是由于感知和技术原因导致过度使用和/或避免使用正则表达式。但是PHP及其用户群具有使它复杂化的一些特性,以及为什么我们在SO上看到更多有关它的问题[需要引用!],并且在那里它们“病态地吸引人”。


1

总的来说,我喜欢正则表达式,我发现它们比我不得不用它们替换的20行代码更易于阅读/理解。简短的正则表达式可以快速阅读和理解,并且相对易于维护(如果表达式发生更改,则只需要一行更改即可,而查看20行代码即可进行更改)。有时它们会被滥用,但其他许多事物也会被滥用。

您可能会看到很多滥用它们的原因是因为您浏览StackOverFlow的PHP部分,因为我确定您知道那里有很多非常不成熟的PHP程序员。


1

为什么正则表达式如此令人着迷?

他们不是。他们实际上是丑陋的。而且难以理解。他们是可憎的,应该尽快被杀死。

话虽如此,我现在要重新调试一个小的Perl应用程序。忍不住了 不幸的是,有时它们仍然是工作的最佳工具。


4
我喜欢说正则表达式既不是“正则”也不是“表达”
Andrew Barber 2010年

2
如果您不理解它们,它们将是丑陋且难以理解的。一旦您达到正则表达式的禅宗,它们就会非常优雅。
丹·雷

1
-1用于确定所有程序员都喜欢晦涩难懂,然后不考虑任何其他可能的解释。...说明为什么您认为它们丑陋或难以理解。
Macneil 2010年

1
@Macneil-请(尽管是的,尽管如此,我的观点还是一样),除非您引用我,否则请不要声明我说/决定了我没有做的事情(您的评论的第一部分)。就您的问题而言,您觉得它们很漂亮吗?... 我不。并且由于这是一个主观站点,并且这是一个主观意见,因此我不必也不想对此进行阐述。为此,我也不会尝试。
Rook

1
@Rook-我认为大多数人会看一个复杂的正则表达式,认为所有正则表达式都很丑陋,然后停止思考。事实是,如果您可以放下对它们的偏见,它们是一种非常优雅且富有表现力的工具。顺便说一句,根据您自己的逻辑,很多程序员不能做代数,所以代数可能天生就是邪恶的,应该被废除,因为它显然不是很容易理解。
丹·雷

0

人是使用工具的生物,正则表达式是强大的工具。正则表达式的一个很好的比喻是熟食店的切肉机。如果您要切成薄片的火鸡,咸牛肉等,仅此而已。但是,您需要熟练的手来使用它,因为您可能会用它严重割伤自己,直到您看到鲜血,您才会有任何感觉。我的意思是,正则表达式的主要问题是使它们稍有偏离,这意味着您匹配了不应该匹配的内容,反之亦然,并且直到过程进一步导致问题时您才发现。


0

正则表达式具有强大的功能,因此非常有吸引力。您可以用很少的字符完成非常复杂的工作。

问题在于标准的正则表达式构造不是图灵完备的,这意味着有些程序根本无法使用正则表达式来实现,人们不知道当它们被正则表达式的强大功能所吸引。

我猜这是“现在他们有两个问题”的原因了。

猜想 Perl正则表达式是图灵完备的,但是显然它还没有被果断地证明或证明。


0

因为这是对有限状态机进行编程的有效方法,所以在应用有限状态机时它是一种强大的工具。基本上,它是用于编程FSM的语言,如果您知道该语言,则很有用,否则您会感到烦恼。


0

在我的经验中,正则表达式就像一门古老的艺术,有些晦涩难懂,有些人讨厌它们,因为它们无法理解所涉及的魔术,也许是因为没人会向您解释它们。我从未听说过大学会教他们比匹配电子邮件更琐碎的东西。然后是它的神秘内部运作,因为大多数人不了解它们,所以它们一定很慢。对于初学者来说,让他们在第一次尝试中正常工作始终是一个挑战。

关于Perl,awk,Linux以及没有闪亮按钮或漂亮彩色语法的所有内容,都可以说同样的话。因此,这就像为“琐碎的任务”增加了复杂性,只是抛出了一些循环,拆分,切换,一些魔术,仅此而已,可能会起作用。但是好吧,如果您在路的另一端,则正则表达式是漂亮的曲奇工具,看起来像信号噪音,没有任何讨厌的循环或更多的东西需要调试。我也喜欢它们提供的灵活性。当匹配的模式发生变化时,您只需更改正则表达式即可,而无需更改算法或工具/其他内容,这很好并且可以重新工作。并且由于它们是一个神奇的字符串,因此您可以根据需要将其放在源代码之外。另外一件让我想到perl的事情是,如果您编写的正则表达式长度超过20个字符,那么您会感觉很不错,至少对我来说,它是如此整洁紧凑。我也是一个懒惰的程序员,我不喜欢编写带有良好标识和注释的大量代码,并且不喜欢添加一些错误。

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.