为啥正则表达式如此有争议? [关闭]

Posted

技术标签:

【中文标题】为啥正则表达式如此有争议? [关闭]【英文标题】:Why are regular expressions so controversial? [closed]为什么正则表达式如此有争议? [关闭] 【发布时间】:2010-10-20 08:07:48 【问题描述】:

在探索正则表达式(也称为 RegEx-es)时,许多人似乎将正则表达式视为圣杯。看起来如此复杂的东西 - 必须是任何问题的答案。他们倾向于认为每个问题都可以使用正则表达式来解决。

另一方面,也有很多人不惜一切代价试图避免使用正则表达式。他们试图找到一种绕过正则表达式的方法,并为此接受额外的编码,即使正则表达式会是一个更紧凑的解决方案。

为什么正则表达式被认为如此有争议?对它们的工作方式是否存在普遍的误解?还是普遍认为正则表达式通常很慢?

【问题讨论】:

如果这是一个讨论,那么不应该关闭它吗?但我在那里看到了一个真正的问题,所以也许讨论标签不属于? 不开玩笑。你提出来,这里的人们开始变得疯狂。 问题中的观察和措辞很好! 另见programmers.stackexchange.com/questions/223634/… 问题是基于意见的,该规则也应适用于此处(或者应编辑问题以提供准确的答案)。也就是说,我认为正则表达式的争议来自关于它的教程和手册的不精确。大多数情况下,如果不是所有时间信息都是混合的,而且我们没有得到所有特征。再加上这种语言的误用,你最终会学到一些东西,在路上会注意到它可能意味着别的东西。最后,特殊的正则表达式字符不仅限于一种含义,这会增加更多的混乱。 【参考方案1】:

“Regular Expressions: Now You Have Two Problems”是 Jeff Atwood 就此事发表的一篇很棒的文章。基本上,正则表达式是“难”的!他们可以制造新的问题。但是,它们是有效的。

【讨论】:

【参考方案2】:

我认为人们反对正则表达式并不是因为它们很慢,而是因为它们很难读写,而且很难正确处理。虽然在某些情况下,正则表达式为问题提供了一种有效、紧凑的解决方案,但它们有时会被硬塞到最好使用易于阅读、可维护的代码部分代替的情况。

【讨论】:

是的,与使用简单函数相比,正则表达式可能非常慢。不仅速度慢,而且当面对任意(用户提供的)输入时,正则表达式引擎的性能可能完全不可预测 如果你知道正则表达式的工作原理,那根本不是问题。 @pacerier,不是慢模式,而是慢引擎。大多数(现代)正则表达式引擎不适合复杂的模式(例如许多|.*),因为它们使用堆栈机器和回溯。这就是为什么您必须仔细调整 Perl、Java、Python、Ruby 中的正则表达式……旧式正则表达式引擎(例如 grep)首先将模式编译为 DFA。之后,模式的复杂性在很大程度上是无关紧要的。我只是使用 Java 和 grep 来处理相同的文本和模式:22 分钟 vs 2 秒。这是科学:swtch.com/~rsc/regexp/regexp1.html【参考方案3】:

正则表达式是一个很棒的工具,但人们认为“嘿,多么棒的工具,我会用它来做 X!”其中 X 是其他工具更适合的东西(通常是解析器)。在需要螺丝刀问题的情况下使用锤子是标准。

【讨论】:

请记住,大多数解析器 - 词法分析器 - 仍然使用正则表达式来解析他们的东西 :-) 说解析器使用正则表达式就像说解析器使用赋值语句。在您查看它们的使用方式之前,这没有任何意义。 当解析器更好时使用正则表达式很烦人。当语言的标准字符串查找或替换函数可以工作时(通常在线性时间内)使用正则表达式是不可原谅的。 同意,因为 RegEx 必须是万事通,它的处理开销是巨大的。仅仅因为使用 RegEx 引擎看起来很容易并不意味着它是迭代解析器(开发人员依赖阈值)的更好解决方案。我最喜欢的例子之一是 phpsplit($pattern,$string)explode($delimiter,$string) - 谢天谢地,前者正在贬值,但很多代码只需要后者的力量时就使用前者。同意,RegEx 提供了一个简单的工具来做一些事情,但除非你需要正则表达式的全部功能,否则它们 Lexical analysers 可能确实使用了正则表达式。它们也被称为标记器,但它们不是syntactic analysers(或解析器)。要读取足够复杂的字符串,应使用标记器将字符串读取为标记(可能使用正则表达式,也可能不使用,具体取决于标记器)。然后将这些标记传递给解析器,解析器将使用绝对不是正则表达式的语法规则来处理它们。【参考方案4】:

您几乎可能会问为什么 goto 会引起争议。

基本上,当你获得如此多“明显”的权力时,人们很容易在他们不是最佳选择的情况下滥用它们。例如,要求在正则表达式中解析 CSV、XML 或 HTML 的人数之多令我震惊。这是工作的错误工具。但是有些用户还是坚持使用正则表达式。

就我个人而言,我试图找到一种快乐的媒介——将正则表达式用于它们的优点,并在它们不是最佳的时候避免它们。

请注意,正则表达式仍可用于解析 CSV、XML、HTML 等。但通常不能在单个正则表达式中。

【讨论】:

当然,您可以在单个正则表达式中解析任何这些格式,这就是正则表达式的力量,宝贝!你是否愿意这样做,完全是另一回事。【参考方案5】:

正则表达式对很多人来说都是一个谜,包括我自己。它工作得很好,但它就像看一个数学方程。尽管有人终于在http://regexlib.com/ 创建了各种正则表达式函数的合并位置,但我很高兴地报告。现在,如果微软只创建一个正则表达式类,它会自动执行许多常见的事情,比如消除字母或过滤日期。

【讨论】:

你没有抓住重点。正则表达式的想法是你花一些时间来学习它们,当你完成后,你不再需要一些神奇的“阅读日期”课程。相反,它们只需要很少的努力正则表达式。此外,为“yyyy/mm/dd”写一个和为“mm-dd-yyyy”写一个一样简单,甚至为“mm-yyyy/dd”写一个(赢得了并不经常发生,但它是一个例子,说明你可以如何做魔法类永远做不到的事情”)。【参考方案6】:

人们倾向于认为正则表达式很难;但那是因为他们用错了。编写没有任何 cmets、缩进或命名捕获的复杂单行语句。 (您不会将复杂的 SQL 表达式塞进一行,没有 cmets、缩进或别名,对吗?)。所以是的,对很多人来说,它们没有意义。

但是,如果您的工作任何都与解析文本(几乎所有的网络应用程序...)有关,并且您不知道正则表达式,那么您的工作就很烂,而且您'正在浪费你自己和你雇主的时间。 excellent resources 可以教你关于他们的一切,你需要知道的,等等。

【讨论】:

嗯 .. 不同之处在于多个空格在正则表达式中有意义,而在其他语言中则没有,这就是为什么它们通常是一个衬垫(有时会换成多行:) @Rado:例如,Perl 具有用于正则表达式的 x 修饰符,导致空格被忽略。这允许您将正则表达式放在几行上并添加 cmets。 同样,Python 有 re.X a.k.a. re.VERBOSE 同样是 tcl 中的 x 修饰符。我相信这是相当标准的,因为 tcl 与其他语言不同,不使用 PCRE。 @AndrewC 这是这篇文章最严重的误解之一。【参考方案7】:

我认为它们没有那么有争议。

我还认为您已经回答了自己的问题,因为您指出在任何地方都使用它们(Not everything is a regular language2)或根本不使用它们是多么愚蠢。作为程序员,您必须对正则表达式何时有助于或损害代码做出明智的决定。面对这样的决定时,需要牢记两件重要的事情是可维护性(这意味着可读性)和可扩展性。

对于那些特别讨厌它们的人,我的猜测是他们从未学会正确使用它们。我认为大多数只花几个小时学习体面教程的人会很快弄清楚并变得流利。以下是我对从哪里开始的建议:

http://docs.python.org/howto/regex

虽然该页面讨论了 Python 上下文中的正则表达式,但我发现这些信息在其他地方非常适用。有一些东西是 Python 特有的,但我相信它们已经被清楚地指出并且容易记住。

【讨论】:

页面似乎已移至docs.python.org/howto/regex @DMan 谢谢。我将编辑我的答案以反映。【参考方案8】:

问题在于正则表达式可能非常强大,以至于你可以用它们做一些你应该使用不同的东西的事情。

一个好的程序员应该知道在哪里使用它们,在哪里不使用它们。典型的例子是解析非常规语言(见Deciding whether a language is regular)。

我认为,如果您一开始将自己限制为 real 正则表达式(无扩展),您不会出错。一些扩展可以让你的生活更轻松一些,但如果你发现某些东西难以用真正的正则表达式表达,这很可能表明正则表达式不是正确的工具。

【讨论】:

【参考方案9】:

正则表达式允许您以紧凑的方式编写自定义有限状态机 (FSM),以处理输入字符串。使用正则表达式难的原因至少有两个:

老式软件开发涉及大量计划、纸模型和仔细思考。正则表达式非常适合这个模型,因为要正确地编写一个有效的表达式需要大量的盯着它,可视化 FSM 的路径。

现代软件开发人员更愿意敲定代码,并使用调试器来逐步执行,以查看代码是否正确。正则表达式不能很好地支持这种工作方式。正则表达式的一次“运行”实际上是一种原子操作。在调试器中很难观察到逐步执行。

编写一个意外接受比您预期更多的输入的正则表达式太容易了。正则表达式的值并不是真正匹配有效输入,而是无法匹配无效输入。对正则表达式进行“否定测试”的技术不是很先进,或者至少没有被广泛使用。

这导致正则表达式难以阅读。仅仅通过查看一个正则表达式,就需要花费很多精力来可视化所有可能的输入,这些输入应该被拒绝,但被错误地接受了。曾经尝试调试过其他人的正则表达式代码吗?

如果今天的软件开发人员对使用正则表达式有抵抗力,我认为主要是由于这两个因素。

【讨论】:

有很多优秀的工具可以调试正则表达式:regexbuddy.com perl -Mre=debug -e "q[aabbcc]=~/ab*[cd]/" 我认为我在看到首字母缩略词“FSM”时不会想到会飞的意大利面怪物。 @Shabbyrobe:我没有冒犯的意思。如果您愿意,可以使用确定性有限自动机 (DFA)。【参考方案10】:

因为他们缺乏普遍接受的 IDE 中最流行的学习工具:没有 Regex Wizard。甚至没有自动完成。您必须自己编写整个代码。

【讨论】:

那么你使用了错误的 IDE... 甚至我的文本编辑器也提供了正则表达式提示。 附带说明,Expresso 和 The Regex Coach 是构建正则表达式的非常有用的工具。 你会如何自动完成正则表达式? EditPad Pro 在搜索框中有正则表达式的语法高亮显示,但我发现它比有用更烦人,因此请关闭它。但我很感激它让我知道当我有无与伦比的括号时;特别是括号可能是一个需要跟踪的熊。 @AmbroseChapel - 我对这个讨论晚了几年。但是我在regexhero.net/tester 创建了一个自动补全机制,它是由圆形()、方形[] 或花括号 括号内的常见构造发起的。它也可以使用反斜杠。【参考方案11】:

虽然我认为正则表达式是必不可少的工具,但最烦人的是它们的实现方式不同。语法、修饰符和——尤其是——“贪婪”的细微差别会使事情变得非常混乱,需要反复试验,有时还会产生令人费解的错误。

【讨论】:

正则表达式实现的最大匹配方法有何不同,我认为您称之为“贪婪”?您是指 leftmost-longestlongest-leftmost 语义之间的区别吗?这是我知道的唯一区别。即,贪婪胜过渴望还是反之亦然【参考方案12】:

我认识的几乎所有经常使用正则表达式(双关语)的人都来自 Unix-ish 背景,他们使用将 RE 视为一流编程结构的工具,例如 grep、sed、awk 和 Perl。由于使用正则表达式几乎没有语法开销,因此他们的工作效率会大大提高。

相比之下,使用 RE 是外部库的语言的程序员往往不会考虑正则表达式可以带来什么。程序员的“时间成本”如此之高,以至于 a) RE 从未作为他们培训的一部分出现,或者 b) 他们不会“思考” RE 的问题,而是更愿意依赖更熟悉的模式。

【讨论】:

是的,我从未原谅 Python 通过使用库使正则表达式语法变得冗长。我认为这是纯洁而不是理智。 我来自 unix 背景,使用过 sed、awk 和 perl 负载,当然也做了很多 grepping,但知道当我使用正则表达式时,我会使用只写的 hack讨厌维护。这对 shell 脚本/一次性计时器很有用,但对于实际工作,对于不只是现在抓取一些数据来保存的任何东西,我现在使用具有清晰语法的适当的分词器/词法分析器/解析器。我最喜欢做所有/任何,干净+可以自我优化。经过多年的努力,我已经学会了,一开始的一点自律意味着以后的努力会更少。正则表达式是键盘上的一瞬间,皱眉是一生。【参考方案13】:

我发现正则表达式有时非常宝贵。当我需要做一些“模糊”搜索时,可能会替换。当数据可能变化并具有一定的随机性时。 但是,当我需要进行简单的搜索和替换或检查字符串时,我不使用正则表达式。虽然我认识很多人这样做,但他们将它用于一切。这就是争议。

如果您想在墙上钉钉子,请不要使用锤子。是的,它会起作用,但是当你拿到锤子时,我可以在墙上钉 20 个大头钉。

正则表达式应该用于它们的设计目的,仅此而已。

【讨论】:

【参考方案14】:

正则表达式的最佳有效和正常用法是用于电子邮件地址格式验证。

这是一个很好的应用。

我在 TextPad 中一次性使用过无数次正则表达式来处理平面文件、创建 csv 文件、创建 SQL 插入语句等等。

写得好的正则表达式不应该太慢。通常替代方案,例如大量调用 Replace 是慢得多的选择。还不如一次性搞定。

许多情况只需要正则表达式即可。

用无害的字符替换特殊的非打印字符是另一个很好的用法。

我当然可以想象有一些代码库过度使用正则表达式而损害了可维护性。我自己从未见过。实际上,我已经被代码审阅者避开了,因为我没有足够地使用正则表达式。

【讨论】:

经验表明,正则表达式实际上是一个很差的电子邮件地址格式验证工具。作为正则表达式实现的真正完整的格式验证器是一个包含数百个字符的怪物,而大多数人需要 5 分钟才能创建的大多数较短的“足够好”的验证器将拒绝大量有效的、可交付的地址。 我听到了,伙计。我说的是“足够好”,虽然理论上大片可能很大,但考虑一下你在这么短的表达中获得的覆盖百分比。我也见过怪物,但你的优雅选择是什么? 我使用了类似 \w@\w+.\w+ 的方式在巨大的文件目录中快速查找电子邮件地址,其中速度很重要,一些误报或误报并不重要。但验证电子邮件地址的最佳方式似乎是向其发送电子邮件。 是的,电子邮件地址规范是一团糟***.com/questions/611775/… @Nick, @Dave: Mail address validation 不必是一团糟。【参考方案15】:

我不认为“有争议”是正确的词。

但是我已经看到很多例子,人们说“我需要什么正则表达式来进行这样那样的字符串操作?”这是 X-Y 问题。

换句话说,他们从假设他们需要正则表达式开始,但他们最好使用 split(),一种类似于 perl 的 tr/// 的翻译,其中字符被替换为其他,或者只是一个 index()。

【讨论】:

【参考方案16】:

正则表达式之于字符串就像算术运算符之于数字,我不会认为它们有争议。我认为即使是像我这样相当激进的OO 活动家(他们倾向于选择其他对象而不是字符串)也很难拒绝它们。

【讨论】:

【参考方案17】:

在某些情况下,我认为您必须使用它们。例如构建一个词法分析器。

在我看来,这是可以写正则表达式的人和不会(或几乎不)写正则表达式的人的观点。 我个人认为这是一个很好的想法,例如验证表单的输入,无论是在 javascript 中警告用户,还是在服务器端语言中。

【讨论】:

【参考方案18】:

我认为这是程序员中鲜为人知的技术。因此,它并没有被广泛接受。如果你有一个非技术经理来审查你的代码或审查你的工作,那么正则表达式是非常糟糕的。您将花费数小时编写一个完美的正则表达式,并且您认为他/她编写的代码行数很少,因此模块得分很少。 此外,正如其他地方所说,阅读正则表达式是一项非常困难的任务。

【讨论】:

只有当编写正则表达式的程序员未能使用空格、cmets、字母数字标识符以及可能通过延迟执行嵌入的子例程时,才能读取正则表达式是一项艰巨的任务。简而言之,所有适用于一般编程的软件工程技术也应该在正则表达式中遵循。如果忽略这些原则,那么作者就没有编写专业的代码。 我认为你的经理不知道“编程的真正英雄是编写负代码的人。” 如果你的经理要赞扬你用 3 行代码(包括正则表达式)完成了这项工作,同时赞扬一些用 900 行汇编程序完成这项工作的愚蠢同事......我建议找一个新工作。【参考方案19】:

这是一个有趣的话题。 许多 regexp 爱好者似乎将公式的简洁性与效率混淆了。最重要的是,一个需要大量思考的 regexp 会给其作者带来巨大的满足感,使其立即合法化.

但是...当性能不是问题并且您需要快速处理文本输出(例如在 Perl 中)时,正则表达式 所以 很方便。此外,虽然性能一个问题,但人们可能不想尝试通过使用可能有错误或效率较低的自制算法来击败正则表达式库。

除了正则表达式受到不公平批评的原因还有很多,例如

正则表达式效率不高,因为构建顶部的表达式并不明显 一些程序员“忘记”只编译一次要多次使用的正则表达式(如 Java 中的静态模式) 一些程序员采用试错法策略 - 使用正则表达式的工作更少!

【讨论】:

【参考方案20】:

使正则表达式可维护

揭开之前被称为“正则表达式”的模式的一个重大进步是 Perl 的 /x 正则表达式标志——在嵌入时有时写为 (?x)——它允许空格(换行、缩进)和 cmets。这大大提高了可读性,从而提高了可维护性。空白区域允许进行认知分块,因此您可以查看哪些组具有哪些内容。

现代模式现在也支持相对编号和命名的反向引用。这意味着您不再需要计算捕获组来确定您需要$4\7。这有助于创建可包含在更多模式中的模式。

这是一个相对编号的捕获组的示例:

$dupword = qr \b (?: ( \w+ ) (?: \s+ \g-1 )+ ) \b xi; $quoted = qr ( ["'] ) $dupword \1 x;

以下是命名捕获的高级方法的示例:

$dupword = qr \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b xi;
$quoted  = qr (?<quote> ["'] ) $dupword  \gquote x;

语法正则表达式

最重要的是,这些命名的捕获可以放在(?(DEFINE)...) 块中,这样您就可以将声明与模式的单个命名元素的执行分开。这使得它们的行为更像是模式中的子例程。 这种“语法正则表达式”的一个很好的例子可以在this answer 和this one 中找到。这些看起来更像是一个语法声明。

正如后者提醒你的那样:

... 确保永远不要编写线路噪声模式。你不必,也不应该。禁止空格、cmets、子例程或字母数字标识符的编程语言是不可维护的。所以在你的模式中使用所有这些东西。

这怎么强调都不过分。当然,如果你不在你的模式中使用这些东西,你经常会制造一场噩梦。但是,如果您确实使用它们,则不需要。

这是现代语法模式的另一个例子,这个用于解析 RFC 5322: 使用 5.10.0;

$rfc5322 = qr

   (?(DEFINE)

     (?<address>         (?&mailbox) | (?&group))
     (?<mailbox>         (?&name_addr) | (?&addr_spec))
     (?<name_addr>       (?&display_name)? (?&angle_addr))
     (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
     (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
     (?<display_name>    (?&phrase))
     (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

     (?<addr_spec>       (?&local_part) \@ (?&domain))
     (?<local_part>      (?&dot_atom) | (?&quoted_string))
     (?<domain>          (?&dot_atom) | (?&domain_literal))
     (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                   \] (?&CFWS)?)
     (?<dcontent>        (?&dtext) | (?&quoted_pair))
     (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

     (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`|~])
     (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
     (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
     (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

     (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
     (?<quoted_pair>     \\ (?&text))

     (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
     (?<qcontent>        (?&qtext) | (?&quoted_pair))
     (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                          (?&FWS)? (?&DQUOTE) (?&CFWS)?)

     (?<word>            (?&atom) | (?&quoted_string))
     (?<phrase>          (?&word)+)

     # Folding white space
     (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
     (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
     (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
     (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
     (?<CFWS>            (?: (?&FWS)? (?&comment))*
                         (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

     # No whitespace control
     (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

     (?<ALPHA>           [A-Za-z])
     (?<DIGIT>           [0-9])
     (?<CRLF>            \x0d \x0a)
     (?<DQUOTE>          ")
     (?<WSP>             [\x20\x09])
   )

   (?&address)

x;

这不是很了不起——而且很棒吗?您可以采用 BNF 样式的语法并将其直接转换为代码,而不会丢失其基本结构!

如果现代语法模式 仍然 对您来说还不够,那么 Damian Conway’s brilliant Regexp::Grammars module 提供了更简洁的语法,并具有出色的调试功能。下面是从该模块解析 RFC 5322 重铸为模式的相同代码:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";

my $rfc5322 = do 
    use Regexp::Grammars;    # ...the magic is lexically scoped
    qr

    # Keep the big stick handy, just in case...
    # <debug:on>

    # Match this...
    <address>

    # As defined by these...
    <token: address>         <mailbox> | <group>
    <token: mailbox>         <name_addr> | <addr_spec>
    <token: name_addr>       <display_name>? <angle_addr>
    <token: angle_addr>      <CFWS>? \< <addr_spec> \> <CFWS>?
    <token: group>           <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
    <token: display_name>    <phrase>
    <token: mailbox_list>    <[mailbox]> ** (,)

    <token: addr_spec>       <local_part> \@ <domain>
    <token: local_part>      <dot_atom> | <quoted_string>
    <token: domain>          <dot_atom> | <domain_literal>
    <token: domain_literal>  <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?

    <token: dcontent>        <dtext> | <quoted_pair>
    <token: dtext>           <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]

    <token: atext>           <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`|~]
    <token: atom>            <.CFWS>? <.atext>+ <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom_text>   <.atext>+ (?: \. <.atext>+)*

    <token: text>            [\x01-\x09\x0b\x0c\x0e-\x7f]
    <token: quoted_pair>     \\ <.text>

    <token: qtext>           <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
    <token: qcontent>        <.qtext> | <.quoted_pair>
    <token: quoted_string>   <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
                             <.FWS>? <.DQUOTE> <.CFWS>?

    <token: word>            <.atom> | <.quoted_string>
    <token: phrase>          <.word>+

    # Folding white space
    <token: FWS>             (?: <.WSP>* <.CRLF>)? <.WSP>+
    <token: ctext>           <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
    <token: ccontent>        <.ctext> | <.quoted_pair> | <.comment>
    <token: comment>         \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
    <token: CFWS>            (?: <.FWS>? <.comment>)*
                             (?: (?:<.FWS>? <.comment>) | <.FWS>)

    # No whitespace control
    <token: NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]

    <token: ALPHA>           [A-Za-z]
    <token: DIGIT>           [0-9]
    <token: CRLF>            \x0d \x0a
    <token: DQUOTE>          "
    <token: WSP>             [\x20\x09]

    x;

;


while (my $input = <>) 
    if ($input =~ $rfc5322) 
        say Dumper \%/;       # ...the parse tree of any successful match
                              # appears in this punctuation variable
    

the perlre manpage 中有很多好东西,但基本正则表达式设计功能的这些显着改进绝不仅限于 Perl。事实上the pcrepattern manpage 可能更容易阅读,并且涵盖了相同的领域。

现代模式与你在有限自动机课上学到的原始东西几乎没有任何共同之处。

【讨论】:

是的!是的!最后,有人展示了一个很好的例子,说明正则表达式使用 x 修饰符的可读性如何。我不敢相信很少有人知道它的存在,更不用说实际使用它了。 @Shabbyrobe:不仅仅是/x。它在语法上使用正则表达式,并带有 (?&amp;name) 内部正则表达式子例程,这真的让它大放异彩。 +1 你总能学到新东西。我不知道 PCRE 对定义有“假”条件。 Python 同样有一个re.VERBOSE 标志。 只是继续说我仍然对人们为了使正则表达式可用而付出的努力感到惊讶。【参考方案21】:

在 lex 和 yacc 中用于编译器定义的正​​则表达式系统很好,非常有用且干净。在这些系统中,表达式类型是根据其他定义的。这是在 perl 和 sed 代码(等)中常见的可怕的畸形不可读的行噪声巨大的单行正则表达式是“有争议的”(垃圾)。

【讨论】:

【参考方案22】:

我认为学习正则表达式和维护正则表达式不受欢迎, 大多数开发人员都很懒惰,或者他们中的大多数人都依赖外部库来为他们做解析……他们依靠谷歌来寻找答案,甚至在论坛上询问他们问题的完整代码。 但是当涉及到实施或修改/维护正则表达式时,它们就会失败。

有一句流行的说法“朋友不要让朋友使用正则表达式解析 HTML”

但就我而言,我已经使用正则表达式制作了完整的 HTML 解析器,我发现正则表达式在解析 html 字符串的速度和内存方面都做得更好(如果你有一个想法,你要实现什么:) )

【讨论】:

我认为把大多数开发人员都写成懒惰是不诚实的。我会说语法非常神秘,不直观,并且对于未启动的人来说充满了陷阱,这导致进入门槛很高。出于同样的原因,Perl 对许多人来说有一个“坏”的名声,但它也是一种非常强大的语言。这就像在您知道符号之前尝试阅读数学表达式。这令人望而生畏,开发人员必须在他们的时间里保持审慎,才能知道他们会从学习该语法中受益。 错过 HTML 中的边缘情况,因为 HTML 不是常规语言。如果您的意图是解析 HTML 的已知子集,那么您是安全的

以上是关于为啥正则表达式如此有争议? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的产品代码的正则表达式不起作用? [关闭]

为啥 Boolean.prototype 又是一个布尔对象? (对于字符串和数字也是如此,但不是日期或正则表达式?)

您能否提供一些示例说明为啥使用正则表达式难以解析 XML 和 HTML? [关闭]

您能否提供一些示例说明为啥使用正则表达式难以解析 XML 和 HTML? [关闭]

为啥用正则表达式解析 XML 是个坏主意? [关闭]

为啥正则表达式构造函数需要双重转义?