学习正则表达式

166

我不是很理解正则表达式。你能够简单易懂地给我解释一下吗?如果有任何在线工具或书籍,你能否也提供链接?

1个回答

856
最重要的部分是概念。一旦你理解了构建块的工作原理,语法上的差异就只是轻微的方言而已。在正则表达式引擎的语法之上,还有你正在使用的编程语言的语法层。像Perl这样的语言消除了大部分的复杂性,但如果你在C程序中使用正则表达式,你仍需要记住其他考虑因素。
如果你把正则表达式看作是可以随意混合和匹配的构建块,它不仅帮助你学习如何编写和调试自己的模式,还能帮助你理解他人编写的模式。
从概念上讲,最简单的正则表达式是字面字符。模式N匹配字符'N'。
相邻的正则表达式匹配序列。例如,模式Nick匹配序列'N'后跟'i'后跟'c'后跟'k'。
如果你曾经在Unix上使用grep,即使只是搜索普通的字符串,你已经在使用正则表达式了!(grep中的re指的是正则表达式。)
稍微增加一点复杂性,你可以用模式[Nn]ick匹配'Nick'或'nick'。方括号中的部分是一个字符类,意味着它恰好匹配其中一个字符。你也可以在字符类中使用范围,所以[a-c]匹配'a'或'b'或'c'。

模式.是特殊的:它匹配任何字符,而不仅仅是一个字面上的句点。在概念上,它与真正大的字符类[-.?+%$A-Za-z0-9...]相同。

将字符类视为菜单:只选择一个。

有用的快捷方式

使用.可以节省大量输入,常见模式还有其他快捷方式。例如,你想匹配一个数字:一种写法是[0-9]。数字是常见的匹配目标,因此你可以使用快捷方式\d。其他的是\s(空白字符)和\w(单词字符:字母数字或下划线)。

大写变体是它们的补集,因此\S匹配任何空格字符,例如。

一次不够

从这里开始,你可以使用量词重复模式的部分。例如,模式ab?c匹配'abc'或'ac',因为?量词使其修改的子模式是可选的。其他量词是

  • *(零次或多次)
  • +(一次或多次)
  • {n}(正好n次)
  • {n,}(至少n次)
  • {n,m}(至少n次,但不超过m次)

将其中一些块组合在一起,模式[Nn]*ick匹配所有以下内容

  • ick
  • Nick
  • nick
  • Nnick
  • nNick
  • nnick
  • (等等)

第一个匹配演示了一个重要的教训:*总是成功!任何模式都可以匹配零次。

另外几个有用的例子:

  • [0-9]+(及其等效的\d+)匹配任何非负整数
  • \d{4}-\d{2}-\d{2}匹配格式为2019-01-01的日期

分组

一个量词修饰其左侧的模式。你可能期望0abc+0匹配'0abc0'、'0abcabc0'等,但是加号量词符号紧贴在c左侧,这意味着0abc+0匹配'0abc0'、'0abcc0'、'0abccc0'等。
要匹配以零为结尾的一个或多个“abc”序列,请使用0(abc)+0。括号表示可作为一个单元进行量化的子模式。正则表达式引擎通常会保存或“捕获”与带括号组匹配的输入文本部分。这种方式提取位更加灵活,比计数索引和substr方法更少出错。

选择

前面我们看到了一种匹配'Nick'或'nick'的方式。另一种方式是使用选择,如Nick|nick。请记住,选择包含其左侧和右侧的所有内容。使用分组括号来限制|的范围,例如(Nick|nick)
例如,您可以将[a-c]等效地写成a|b|c,但这可能不是最佳选择,因为许多实现假定备选项的长度大于1。

转义

尽管某些字符与它们自身匹配,其他字符具有特殊含义。模式\d+不匹配反斜杠后跟小写字母D后跟加号:要获得该结果,我们需要使用\\d\+。反斜杠会去除下一个字符的特殊含义。
贪婪性
正则表达式量词是贪婪的。这意味着它们尽可能地匹配尽可能多的文本,同时允许整个模式成功匹配。
例如,假设输入为:
"Hello," she said, "How are you?"
你可能期望".+"仅匹配'Hello,',但当你发现它从'Hello'一直匹配到'you?'时,你会感到惊讶。
要从贪婪模式切换到谨慎模式,请在量词中添加额外的?。现在你明白了你的问题中的示例\((.+?)\)是如何工作的。它匹配一个文字左括号,后跟一个或多个字符,并以右括号终止的序列。
如果你的输入是'(123) (456)',那么第一个捕获将是'123'。非贪婪量词希望尽快允许其余模式开始匹配。
(至于你的困惑,我不知道任何正则表达式方言可以使((.+?))做同样的事情。我怀疑在传输过程中某些内容丢失了。)
锚点
使用特殊模式^匹配输入的开头,使用$仅匹配结尾。在您的模式中制作“书框”,其中您说:“我知道前面和后面是什么,但请给我中间的所有内容”是一种有用的技术。
假设您想匹配以下形式的注释
-- This is a comment --
您可以编写^--\s+(.+)\s+--$

构建自己的正则表达式

正则表达式是递归的,因此现在您已经了解了这些基本规则,可以随意组合它们。

编写和调试正则表达式的工具:

书籍

免费资源

脚注

†: 上述说法中的.匹配任何字符是为了教学目的而进行的简化,严格来说并不正确。点号匹配除换行符"\n"以外的任何字符,但在实践中,您很少期望像.+这样的模式跨越换行边界。例如,Perl正则表达式有一个/s开关,Java有Pattern.DOTALL,可以使.匹配任何字符。对于没有此功能的语言,您可以使用类似[\s\S]的方法来匹配“任何空白或任何非空白”,换句话说就是任何东西。


17
你还可以使用试错法,然后使用在线正则表达式测试器和调试器,这将非常有帮助:https://regex101.com/ - Juraj.Lorinc
3
值得一提的是,在Javascript、Perl和Python中,尽管它们具有相似的模式,但类似于a{,m}这样的写法并不存在。 - anon
4
值得一提的是,存在不同种类的正则表达式引擎,它们具有不同的功能集和语法规则。 - hek2mgl
1
https://hackr.io/tutorials/learn-regular-expressions-regex 是一个很好的地方,可以找到最好的在线正则表达式教程。这里的所有教程都是由编程社区提交和推荐(像 SO 一样进行投票)。 - Saurabh Hooda
1
如果有任何初学者因为资源数量而感到不知所措,只是想要一个简单的介绍,那么在“免费资源”中给出的第一个链接 https://regexone.com 对于学习基础知识非常好。 - Freelancer
显示剩余2条评论

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