在探索正则表达式(也称为RegEx-es)时,有许多人似乎将正则表达式视为圣杯.看起来如此复杂的东西 - 只是必须回答任何问题.他们倾向于认为使用正则表达式可以解决所有问题.
另一方面,也有许多人试图不惜一切代价避免使用正则表达式.他们试图找到解决正则表达式的方法并接受额外的编码只是为了它,即使正则表达式是一个更紧凑的解决方案.
为什么正则表达式被认为是如此有争议?是否存在关于它们如何工作的普遍误解?或者可能是一个普遍的信念,正则表达式通常很慢?
Kyl*_*nin 133
我不认为人们会反对正则表达式因为它们很慢,而是因为它们难以读写,而且很难做到正确.虽然在某些情况下正则表达式为问题提供了有效,紧凑的解决方案,但有时它们会被用于更好地使用易于阅读,可维护的代码段的情况.
Joe*_*ger 121
揭开以前被称为"正则表达式"的模式的一个重大进展是Perl的/x正则表达式标志 - 有时(?x)在嵌入时写入- 允许空格(换行,缩进)和注释.这严重提高了可读性,从而提高了可维护性.白色空间允许认知分块,因此您可以看到哪些组具有什么.
现在,现代模式现在也支持相对编号和命名的反向引用.这意味着您不再需要计算捕获组以确定您需要$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 \g{quote} }x;
Run Code Online (Sandbox Code Playgroud)
最重要的是,这些命名的捕获可以放在一个(?(DEFINE)...)块中,这样您就可以将声明与模式中各个命名元素的执行分开.这使它们的行为更像是模式中的子程序.
这个"语法正则表达式"的一个很好的例子可以在这个答案和这个答案中找到.这看起来更像是语法宣言.
正如后者提醒您:
...确保永远不要写线?噪音模式.你不必,你不应该.没有编程语言可以维护,禁止使用空格,注释,子例程或字母数字标识符.所以在你的模式中使用所有这些东西.
这不能过分强调.当然,如果你不在你的模式中使用这些东西,你经常会制造一个噩梦.但是,如果您确实使用它们,则不需要.
这是现代语法模式的另一个例子,这个用于解析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) | (?"ed_string))
(?<domain> (?&dot_atom) | (?&domain_literal))
(?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
\] (?&CFWS)?)
(?<dcontent> (?&dtext) | (?"ed_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) | (?"ed_pair))
(?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
(?&FWS)? (?&DQUOTE) (?&CFWS)?)
(?<word> (?&atom) | (?"ed_string))
(?<phrase> (?&word)+)
# Folding white space
(?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
(?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
(?<ccontent> (?&ctext) | (?"ed_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;
Run Code Online (Sandbox Code Playgroud)
这不是那么了不起 - 而且很精彩?您可以采用BNF风格的语法并将其直接转换为代码而不会失去其基本结构!
如果说现代语法结构仍然是不够的你,那么达米安康威的辉煌Regexp::Grammars模块提供了一个更清洁的语法,具有超强的调试,太.以下是将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
}
}
Run Code Online (Sandbox Code Playgroud)
有一个在很多好东西的perlre手册页,但在基本的正则表达式的设计特点,这些显着改善绝不单单局限于Perl的手段.实际上,pcrepattern手册页可能更容易阅读,并涵盖相同的领域.
现代模式与你在有限自动机类中教授的原始事物几乎没有任何共同之处.
Cha*_*ens 68
正则表达式是一个很好的工具,但人们认为"嘿,这是一个很棒的工具,我会用它做X!" 其中X是不同工具更适合的东西(通常是解析器).这是使用锤子的标准,你需要一个螺丝刀问题.
Bar*_*own 52
几乎每个我认识的人经常使用正则表达式(双关语)来自Unix-ish背景,他们使用将RE作为一流编程结构的工具,如grep,sed,awk和Perl.由于使用正则表达式几乎没有语法上的开销,因此当他们这样做时,他们的工作效率会提高.
相比之下,使用RE是外部库的语言的程序员往往不会考虑正则表达式可以带到表中的内容.程序员的"时间成本"是如此之高,以至于a)REs从未作为他们培训的一部分出现,或者b)他们没有在RE方面"思考"并且更愿意依赖于更熟悉的模式.
Bil*_*win 44
正则表达式允许您以紧凑的方式编写自定义有限状态机(FSM),以处理输入字符串.使用正则表达式很难有至少两个原因:
老派软件开发涉及很多规划,纸模型和仔细思考.正则表达式非常适合这个模型,因为正确地编写一个有效的表达式需要大量的盯着它,可视化FSM的路径.
现代软件开发人员更愿意敲定代码,并使用调试器逐步执行,以查看代码是否正确.正则表达式不能很好地支持这种工作方式.正则表达式的一个"运行"实际上是原子操作.很难在调试器中观察逐步执行.
编写一个偶然接受比你想要的更多输入的正则表达式太容易了.正则表达式的值实际上并不匹配有效输入,而是无法匹配无效输入.对正则表达式进行"否定测试"的技术不是很先进,或者至少没有广泛使用.
这使得正则表达式难以阅读.仅仅通过查看正则表达式,需要大量注意力来可视化应该被拒绝的所有可能的输入,但是被错误地接受.曾经尝试调试其他人的正则表达式代码?
如果今天软件开发人员对使用正则表达式有抵触,我认为这主要是由于这两个因素.
Jas*_*ers 37
人们倾向于认为正则表达很难; 但那是因为他们错了.编写复杂的单行,没有任何注释,缩进或命名捕获.(你不要在一行中填写复杂的SQL表达式,没有注释,缩进或别名,不是吗?).是的,对很多人来说,他们没有意义.
但是,如果你的工作有什么做解析文本(大致任何Web应用程序在那里......),你不知道正则表达式,你吮吸你的工作,你是在浪费自己的时间和你的雇主.有很好的资源可以教你一些你需要知道的关于它们的信息,等等.
dkr*_*etz 29
因为它们缺乏普遍接受的IDE中最流行的学习工具:没有正则表达式向导.甚至没有Autocompletion.你必须自己编写所有的东西.
all*_*ode 16
我不认为他们是那么有争议.
我也认为你已经回答了自己的问题,因为你指出在任何地方使用它们是多么愚蠢(不是所有东西都是常规语言 2)或者完全避免使用它们.作为程序员,您必须明智地决定正则表达式何时会帮助代码或者对代码造成伤害.面对这样的决定时,要记住的两个重要事项是可维护性(这意味着可读性)和可扩展性.
对于那些特别厌恶他们的人,我的猜测是他们从未学过如何正确使用它们.我认为大多数只花几个小时使用体面教程的人会把它们搞清楚,并且很快就会流利.这是我建议从哪里入手:
http://docs.python.org/howto/regex
虽然该页面讨论了Python上下文中的正则表达式,但我发现这些信息在其他地方非常适用.有一些特定于Python的东西,但我相信它们清楚地被注意到,并且易于记忆.
我认为“有争议”这个词并不合适。
但我见过很多例子,人们说“我需要什么正则表达式来进行这样那样的字符串操作?” 这是 XY 问题。
换句话说,他们一开始就假设正则表达式就是他们所需要的,但他们最好使用 split(),一种类似于 Perl 的 tr/// 的翻译,其中字符被一个替换为另一个,或者只是一个索引()。
你几乎可以问为什么goto是有争议的.
基本上,当你获得如此"明显"的力量时,人们很容易滥用它们,因为它们不是最好的选择.例如,要求在正则表达式中解析CSV或XML或HTML的人数让我震惊.这是工作的错误工具.但是有些用户仍坚持使用正则表达式.
就个人而言,我试图找到快乐的媒介 - 使用正则表达式来获取它们的优点,并在它们不是最佳时避免使用它们.
请注意,正则表达式仍可用于解析CSV,XML,HTML等.但通常不在单个正则表达式中.
| 归档时间: |
|
| 查看次数: |
36583 次 |
| 最近记录: |