杰米·扎温斯基(Jamie Zawinski)的一句话很流行:现在他们有两个问题。
应该怎么理解这句话?
#1 楼
某些编程技术通常不为程序员所理解(正则表达式,浮点,Perl,AWK,IoC等)。问题。正则表达式对于匹配正则语言特别有用。问题的症结在于:很少有人知道如何描述常规语言(这是计算机科学理论/语言学的一部分,它使用有趣的符号-您可以在乔姆斯基体系中进行阅读)。处理这些问题时,如果使用不当,就不可能真正解决您原来的问题。使用正则表达式来匹配HTML(这太常见了)将意味着您将错过边缘情况。现在,您仍然遇到了尚未解决的原始问题,并且通过使用错误的解决方案引入了另一个细微的错误。这并不是说正则表达式不应该使用,而是应该努力理解它们可以解决,不能明智地解决和解决的问题集。
维护软件的关键是编写可维护的代码。使用正则表达式可能会违反该目标。在使用正则表达式时,您已经使用特定领域特定的语言编写了小型计算机(特别是非确定性有限状态自动机)。用这种语言编写“ Hello world”等价物很容易,并获得了基本的信任,但是需要对常规语言的理解来锻炼自己,以避免编写可能很难识别和修复的其他错误(因为它们不是正则表达式所在程序的一部分。)
因此,现在您遇到了一个新问题;您选择了正则表达式的工具来解决它(当不合适时),现在您遇到了两个错误,因为它们被隐藏在另一层抽象中,所以很难找到它们。
评论
我不确定perl本身是否属于程序员不容易理解的技术列表;)
–疯狂
2014年1月9日在22:02
@crad还有更多关于perl的说法……很多人听说过它在那里流行。我仍然喜欢兰德谈话中的浮点数:“现在您有2.00000152个问题”
–user40980
2014年1月9日在22:05
@crad有些人在遇到问题时会认为“我知道,我会使用perl”。现在他们遇到了$(^ @#%()^%)(#)问题。
–迈克尔·汉普顿
2014年1月10日,0:54
@Jens,如果有的话,PCRE与传统regex相比具有的强大功能使它成为更诱人的解决方案,并且更难以维护。在扩展有限自动机以有效地匹配Perl兼容的正则表达式中探索了PCRE匹配的有限自动机...这是一件很简单的事情。至少使用传统的正则表达式,一旦了解了必要的概念,就可以毫不费力地绕开它。
–user40980
2014年1月10日15:23
你说的对。正则表达式实际上是第二种平凡的语言。即使原始程序员能胜任主要语言和所使用的正则表达式的风格,添加“第二种语言”也意味着维护人员会同时了解两者的几率较低。更不用说正则表达式的可读性通常低于“宿主”语言。
– JS。
2014年1月10日18:25
#2 楼
正则表达式-特别是非琐碎的正则表达式-可能难以编码,理解和维护。您只需要查看标记为[regex]
的Stack Overflow上的问题数量,其中发问者假设其问题的答案是正则表达式,并且随后陷入困境。在很多情况下,可以(也许应该)以其他方式解决问题。这意味着,如果您决定使用正则表达式,则现在有两个问题:
您想解决的原始问题。
正则表达式的支持。
基本上,我认为他的意思是,如果没有其他方法可以使用正则表达式解决您的问题。另一个解决方案可能会更易于编码,维护和支持。它可能会变慢或降低效率,但是如果不是很关键,那么维护和支持的简便性应该是首要考虑的问题。
评论
更糟糕的是:它们的功能足以欺骗人们尝试使用它们来解析他们无法解析的内容,例如HTML。在SO上看到有关“如何解析HTML”的众多问题。
–坦率的剪毛
2010-10-11 14:53
在某些情况下,正则表达式很棒。在许多其他情况下,情况并非如此。另一方面,这是一个令人绝望的恐怖坑。当某人第一次了解它们并开始在各处看到应用程序时,通常会出现此问题。另一句著名的名言:“当您拥有的唯一工具是锤子时,一切看起来就像钉子。”
–托德·威廉姆森(Todd Williamson)
2010-10-11 15:10
这是否意味着通过SO [c#]标记中的问题数量,它是最难理解的编程语言?
–罗杰·佩特
2010-10-29 9:45
我宁愿看到一个复杂的正则表达式,而不是一连串的字符串方法调用。 OTOH,我真的很讨厌看到正则表达式被滥用来解析复杂的语言。
–kevin cline
2011年5月20日下午3:57
“基本上,我认为他的意思是,只有在没有其他方法可以解决您的问题时,才应使用正则表达式。任何其他解决方案将更易于编码,维护和支持。” -严重不同意。正则表达式是出色的工具,您只需要知道其局限性即可。可以使用正则表达式对许多任务进行更优雅的编码。 (但是,仅举一个例子,您不应使用它们来解析HTML)
–卡洛莉·霍瓦斯(Karoly Horvath)
2011-12-5 23:30
#3 楼
尽管有一定的道理,但这主要是开玩笑的笑话。我曾经用一个正则表达式替换了500行手动编写的递归下降解析器代码,而这大约需要10分钟才能完全调试。人们说正则表达式很难理解和调试,但是适当应用的正则表达式几乎不像手工设计的大型解析器那么难调试。在我的示例中,花了两周时间调试了非正则表达式解决方案的所有边缘情况。表现力是责任。 br />对于正则表达式来说,有些东西最初看起来很不错,但事实并非如此。例如,任何带有嵌套标记的东西,例如HTML。当更简单的方法更清晰时,有时人们使用正则表达式。例如,
string.endsWith("ing")
比等效的正则表达式更易于理解。有时,人们尝试将一个大问题塞入一个正则表达式中,在这种情况下,将其分解为更合适的方法。有时人们无法创建适当的抽象,一遍又一遍地重复一个正则表达式,而不是创建一个功能强大的函数来完成相同的工作(也许是在正则表达式内部实现的)。 由于某种原因,正则表达式有一种怪异的趋势,可为常规软件工程原则(如单一职责和DRY)造成盲点。这就是为什么即使是爱他们的人有时也会发现他们有问题的原因。
评论
本叔叔还不是每次都说“完美的结果”吗?也许这就是为什么人们如此对正则表达式感到满意的原因...
–安德烈·道尔(Andrzej Doyle)
2014年1月10日15:52
正则表达式的有关HTML的问题使经验不足的开发人员感到震惊,原因是HTML具有上下文无关的语法,而不是常规语法:正则表达式可用于某些简单的HTML(或XML)解析(例如,从命名锚标签中获取URL),但是不太适合任何复杂的事情。为此,DOM解析更为合适。相关阅读:Chomsky层次结构。
–user22815
2015年3月3日,下午3:17
#4 楼
杰夫·阿特伍德(Jeff Atwood)在讨论此报价的博客文章中提出了不同的解释:正则表达式:现在您有两个问题(感谢链接的欣快感)在最初的1997年主题中发帖,我们发现以下内容:Perl的本性鼓励使用正则表达式,几乎将所有其他技术排除在外;它们是从A点到B点的最“明显”(至少对于不了解的人来说)最远的方式。第一个引用是太无礼了,不能当真。但是,我完全同意。这就是杰米(Jamie)试图提出的要点:并不是说正则表达式本身就是邪恶的,而是过度使用正则表达式是邪恶的。
即使您完全了解正则表达式,您也可以碰到Golden Hammer问题,试图用正则表达式解决问题,而用正则代码做同一件事会更容易和更清楚(另请参阅CodingHorror:Regex使用与Regex滥用)。
另一篇博客文章探讨了报价的上下文,并且比Atwood更为详细:Jeffrey Friedl的博客:著名的“现在有两个问题”报价的来源
评论
在我看来,这是最好的答案,因为它增加了上下文。 jwz对正则表达式的批评与Perl一样多。
– Evicatos
2014年1月9日在20:15
@Evicatos在另一个博客文章中,对同一1997年线程进行了更多研究:regex.info/blog/2006-09-15/247
–IQAndreas
2014年1月9日20:30
#5 楼
这个引用有一些事情要解决。面对一个问题,有人说“让我们使用AWK”。现在,他们有两个问题。 — D. Tilbrook这是一个玩笑,是一个真实的发现,但它也是通过将正则表达式与其他不良解决方案联系起来来强调正则表达式的一种方式。这是一个很棒的时刻,只有严肃的时刻。仅仅宣布使用正则表达式的想法并不能解决问题。此外,您还添加了其他语言,其规则与您使用的任何语言都不同,从而增加了代码的认知复杂性。
虽然很有趣,但您需要比较非regex解决方案,包括regex解决方案的复杂性+包含regexes的其他复杂性。尽管添加正则表达式会产生额外费用,但解决正则表达式问题可能还是值得的。
#6 楼
正则表达式现在或setoreador保留比任何其他未格式化的内容都正确;的确确实希望这条文本可以读到这部分文本,但不幸的是,由于某些实现方式不允许进行格式化,而人们却不愿意接受这种格式,因此它很容易理解。比在任何情况下阅读此正则表达式确实要容易。不幸的是,它们的声誉很差,因为某些实现不允许格式化,而且一般人都不知道您可以做到这一点。)
^(?:[^,]*+,){21}[^,]*+$
其实并不是很难阅读或维护,但是看起来像这样更容易: br />
上面的例子(评论
$
类似于评论i++
)有点明显,但是阅读,理解和维护它应该没有问题。 /> ,只要您清楚何时适合使用正则表达式以及何时不适合使用正则表达式,就不会有任何问题,而且大多数情况下JWZ引用实际上并没有适用。 >
评论
可以,但是我不是在寻求有关正则表达式优点的讨论,并且我也不想看到这种讨论。我只是想了解他的意思。
– Paul Biggar
2010-10-11 14:05
然后,livibetter注释中的链接会告诉您您需要了解的内容。此响应只是指出正则表达式不需要晦涩难懂,因此引号是无稽之谈。
– Peter Boughton
2010-10-11 14:57
使用* +有什么意义?与*相比(功能上)有何不同?
– Timwi
2011年1月12日在18:38
尽管您说的可能是对的,但它并不能回答这个特定问题。您的回答可以归结为“我认为报价通常不正确”。问题不是关于它是否正确,而是报价的含义。
–布莱恩·奥克利(Bryan Oakley)
2011-12-5 23:40
在这种情况下,执行* +毫无意义。所有内容都已锚定,并且可以由最多可计数22个的自动机一次性匹配。这些非逗号集上的正确修饰符只是普通的旧*。 (此外,这里的贪婪和非贪婪匹配算法之间也应该没有区别。这是一个非常简单的情况。)
–研究员
13年4月8日在8:08
#7 楼
除了ChrisF的答案-正则表达式“很难编码,理解和维护”之外,更糟糕的是:它们仅强大到足以欺骗人们尝试使用它们来解析无法解析的内容(例如HTML)。在SO上看到有关“如何解析HTML”的众多问题。例如,所有SO中最史诗般的答案!#8 楼
正则表达式非常强大,但是它们有一个小问题和一个大问题。它们很难写,几乎无法阅读。如果您没有正确地使用正则表达式,则既有原始问题,也有不可读代码无法正常工作的问题。面对需要修复的正则表达式,从头开始通常比尝试理解该表达式要快。评论
真正的问题是正则表达式无法实现例如解析器,因为它们无法计算当前嵌套的深度。
–user1249
2011年8月7日9:21
@ThorbjørnRavn Andersen:这更多的是限制而不是问题。如果您尝试使用正则表达式只是一个问题,那么正则表达式就不成问题,方法选择就不成问题。
–古法
11年8月7日在11:28
您可以对词法分析器使用很好的RE(对于大多数语言而言),但是将令牌流组装到解析树中(即解析)在形式上超出了它们。
–研究员
2011年12月6日15:56
#9 楼
问题在于正则表达式是一个复杂的野兽,只有完美使用正则表达式才能解决问题。如果不这样做,最终会遇到两个问题:您原来的问题和正则表达式。您声称它可以完成一百行代码的工作,但是您还可以提出以下论点100行清晰,简洁的代码比一行正则表达式要好。
如果您需要一些证明:您可以查看此SO Classic或简单地通过SO Regex标签进行梳理
评论
您第一句话中的任何说法都不正确。正则表达式并不是特别复杂,并且像其他任何工具一样,您也需要完全了解它才能解决问题。那只是FUD。您的第二段很荒谬:您当然可以提出争议。但这不是一个好人。
–康拉德·鲁道夫(Konrad Rudolph)
2014年1月10日10:21
@KonradRudolph我认为有许多正则表达式生成和验证工具的事实表明正则表达式是一种复杂的机制。它不是人类可读的(通过设计),并且可能会导致某些人修改或编写使用正则表达式的代码而导致流程的完全改变。至于第二部分,我认为这很明显是因为P.SE上的知识渊博,这意味着“调试代码是编写代码的两倍,因此,如果编写最聪明的代码,从定义上讲,还不足以调试它”
–安培
2014年1月10日16:30
那不是适当的论点。是的,请确保正则表达式很复杂。但是其他编程语言也是如此。正则表达式比大多数其他语言要复杂得多,并且用于正则表达式的工具与其他语言的开发工具相比显得微不足道(FWIW,我广泛使用正则表达式,但我从未使用过此类工具……)。这是一个简单的事实,即使是复杂的正则表达式也比等效的非正则表达式解析代码更简单。
–康拉德·鲁道夫(Konrad Rudolph)
2014年1月10日17:29
@KonradRudolph我认为我们当时对“简单”一词的定义存在根本分歧。我会告诉您,正则表达式可以更有效,甚至更强大,但是当您想到正则表达式时,任何人都不会想到这个简单的词。
–安培
2014年1月11日在4:54
也许可以,但是我的定义是可行的:我的意思很简单,易于理解,易于维护,隐藏的bug少等。当然,乍看之下,复杂的regex乍一看并不是很容易理解。但是对于等效的非正则表达式代码段也是如此。我从未说过正则表达式很简单。我是说它们比较简单-我是在比较。那很重要
–康拉德·鲁道夫(Konrad Rudolph)
2014年1月11日在10:03
#10 楼
含义包括两个部分:首先,您没有解决原始问题。这可能是指正则表达式通常无法提供常见问题的完整解决方案这一事实。
其次,您现在添加了与选择的解决方案相关的其他难度。
对于正则表达式,该附加难度可能涉及复杂性,可维护性,或者与制作正则表达式相关的其他难度解决了原本不应解决的问题。
#11 楼
当您在2014年提出要求时,将重点放在1997年上下文的编程语言意识形态与今天的上下文相比会很有趣。我不会在这里进行辩论,但是有关Perl和Perl本身的观点已经发生了很大变化。但是,为了保持2013年的景象(de l'eau acoulésous les ponts depuis),我建议着重于使用著名的XKCD漫画重新引用报价,该漫画是杰米的直接报价Zawinski的漫画:
首先,我很难理解这部漫画,因为它是对Zawinski语录的引用,以及Jay-z歌曲歌词的语录,以及GNU
program --help -z
flag2的参考,因此,对我来说太过文化了。 我知道这很有趣,我感觉到了,但是我真的不知道为什么。人们经常在开玩笑关于Perl和正则表达式的笑话,特别是因为它不是最时髦的编程语言,所以并不真正知道为什么它应该很有趣……也许是因为Perl的销售商们做的很愚蠢。因此,最初的报价似乎是基于现实生活中的问题(痛苦吗?就像锤子可能会伤害泥瓦匠一样,使用开发人员可能会伤害的工具(大脑,感情)进行编程。有时,关于哪种工具最好的争论很多,但这几乎毫无用处,因为这是您的口味或编程团队的口味,文化或经济原因的问题。关于此的另一本出色的XKCD漫画:
我能理解人们对正则表达式的痛苦,他们相信另一种工具更适合正则表达式的设计。 @ karl-bielefeldt以高表现力回答您的问题时,责任重大,而正则表达式对此尤为关注。如果开发人员不关心S-他如何处理正则表达式,最终将对以后维护代码的人造成痛苦。
我将用引号重演来结束这个答案,引号显示了Damian Conw ay的Perl Best Practices(2005年一本书)中的典型示例。
m{'[^\']*(?:\.[^\']*)*'}
...比编写这样的程序更受人们的欢迎:
sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;
但是可以重写,它仍然不是很漂亮,但是至少现在可以生存。可读的方式。
评论
/ *将数组中的前10个值乘以2。* / for(int i = 0 / *循环计数器* /; i <10 / *小于10时继续* /; ++ i / *和在每次迭代中将其递增1 * /){array [i] * = 2; / *将数组中第i个元素加倍* /}
– 5gon12eder
2015年5月11日在18:14
#12 楼
如果您应该从计算机科学中学到一件事,那就是乔姆斯基层次结构。我要说的是,正则表达式的所有问题都来自尝试用它来解析上下文无关的语法。当您可以对CFG中的嵌套级别施加限制(或认为可以施加限制)时,您将获得那些冗长而复杂的正则表达式。评论
是!在没有CS背景的情况下学习正则表达式的人并不总是了解正则表达式在数学上无法完成某些工作。
– benzado
2011年6月22日在16:49
#13 楼
正则表达式比全面解析更适合于标记化。但是,程序员需要解析的一大堆东西可以用常规语言来解析(或者更糟的是,可以用常规语言来解析,如果您只编写更多的代码…… )。
因此,如果习惯于“啊哈,我需要将文本分开,我将使用正则表达式”,那么当您需要更接近的内容时,很容易沿此路线下推式自动机,CFG解析器或功能更强大的语法。通常,这会以眼泪结束。对正则表达式的依赖(或者确切地说,是对它们的非严格选择)。
#14 楼
jwz的那句话简直让他摇摇欲坠。正则表达式与任何语言功能都没有什么不同-容易搞砸,难以优雅地使用,有时功能强大,有时不适当,通常有据可查,经常有用。点算术,闭包,面向对象,异步I / O或其他您可以命名的东西。如果您不知道自己在做什么,那么编程语言会让您感到难过。
如果您认为正则表达式很难阅读,请尝试阅读等效的解析器实现以使用有问题的模式。正则表达式之所以会获胜,是因为它们比完整的解析器更紧凑...而且在大多数语言中,它们也更快。因为自我提升的博客作者发表了不合格的声明。自己动手做,看看什么对您有用。
评论
FWIW,浮点算术比RE更加棘手,但看起来更简单。谨防! (至少棘手的RE看起来很危险。)
–研究员
2011年12月6日15:59
#15 楼
我最喜欢的深入解答是著名的罗伯·派克(Rob Pike)在一篇博客文章中给出的,该博客文章是从Google内部代码注释中转载的: in-lexing-and.html摘要不是说它们不好,而是它们经常用于不一定适合的任务,特别是在进行词法分析输入。 (如果不是那么紧凑),并且非常容易测试。考虑查找字母数字标识符。编写正则表达式不是太难(像“ [a-ZA-Z _] [a-ZA-Z_0-9] *”之类),但实际上写一个简单的循环并不难。但是,循环的性能将更高,并且涉及的代码更少。正则表达式库是一件大事。用一个解析标识符就像使用法拉利去商店喝牛奶。
他还说了很多,他说正则表达式在例如文本编辑器中模式的一次性匹配,但很少在编译代码中使用,依此类推。值得一读。
#16 楼
这与艾伦·珀利斯(Alan Perlis)的句号#34相关:它是隐藏信息的理想工具。因此,如果您选择字符串作为数据结构(自然而然,将基于正则表达式的代码作为操作它的算法),就会遇到问题,即使它起作用:围绕不恰当的数据表示进行的不良设计也难以扩展,并且效率低下。这样的话你有两个问题。
#17 楼
正则表达式广泛用于快速而肮脏的文本解析。它们是表达模式的好工具,其模式比简单的字符串匹配要复杂得多。正则表达式的语法已针对简单匹配进行了优化,大多数字符都与自己匹配。这对于简单的模式非常有用,但是一旦您完成了多个嵌套级别,您最终将看到的东西看起来更像是行噪声而不是结构良好的代码。我猜您可以将正则表达式编写为一系列连接的字符串,中间带有缩进和注释,以显示代码的结构,但是这种情况实际上很少见。非常适合正则表达式。通常,您会发现自己得到了一种基于正则表达式的快速而又肮脏的解析器,用于某种标记语言,但是随后尝试覆盖更多的极端情况,发现正则表达式变得越来越复杂,可读性也越来越差
时间复杂性正则表达式的含义可能不是很清楚。最终得出一个模式,当它匹配时效果很好,但是在某些不匹配的情况下具有O(2 ^ n)复杂度,并不是很困难。一个文本处理问题,对其应用正则表达式,最后遇到两个问题,即您要解决的原始问题和处理正试图解决(但未正确解决)原始问题的正则表达式。
评论
第二个问题是他们正在使用正则表达式,但仍未解决第一个问题,因此有两个问题。@Euphoric-实际上,好的代码很短-但没有含糊的简洁。
@IQAndreas:我认为这是半幽默的。评论是,如果您不小心,使用正则表达式会使情况变得更糟,而不是更好。
有些人在尝试解释某些内容时会想到“我知道,我将使用Jamie Zawinski的语录”。现在他们有两件事要解释。
程序员遇到了问题。他心想,“我知道,我会用线程解决的!”现在有问题。两个他