本节书摘来自异步社区《正则表达式经典实例(第2版)》一书中的第2章,第2.1节,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章节内容可以访问云栖社区“异步社区”公众号查看
第 2 章 正则表达式的基本技能
本章要讲解的问题并不是老板或客户会要求你解决的那一类现实世界中的问题。相反,它们是在你创建和编辑正则表达式来解决现实世界问题的过程中会遇到的技术性问题。例如,第一个实例会解释如何使用一个正则表达式来匹配字面文本(literal text),以及如何处理正则表达式中有特殊含义的字符。这个问题本身并不是很重要,因为如果你只是要查找字面文本,并不需要使用正则表达式。但是,当创建正则表达式的时候,你可能会需要按照字面来匹配某些文本,那么你就需要知道哪些字符需要转义。实例2.1会告诉你该如何实现。
本章前一部分的实例会讲解一些非常基本的正则表达式技术。如果以前使用过正则表达式,那么你大概可以略读或者甚至是跳过它们。除非你已经从头到尾认真读过Jeffrey E. F. Friedl所著的《精通正则表达式》(Mastering Regular Expression)一书,否则在本章后一部分所给出的实例一定会教给你些新的东西。
本章实例的安排方式是每个实例会讲解正则表达式语法的一个方面。所有这些实例加在一起就形成了一份关于正则表达式的全面指南。读者可以先从头到尾读完本章以做到深入领会正则表达式。或者读者也可以直接跳到第4~第8章中讲解的现实世界中的正则表达式,而当在那些章节中遇到你不是很熟悉的语法时,再按照给出的引用跳回来阅读本章中的相应内容。
2.1 匹配字面文本
问题描述
创建一个正则表达式来严格匹配下面这个复杂的句子:
The punctuation characters in the ASCII table are: !"#$%&'()*+,-./:;<=>?@[\] ^_`{|}~.
此实例用于演示哪些字符在正则表达式中有特殊含义,而哪些字符永远按字面匹配它们自身。
解决方案
The●punctuation●characters●in●the●ASCII●table●are:●↵
!"#\$%&'\(\)\*\+,-\./:;<=>\?@\[\\]\^_`\{\|}~
正则选项:无
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby
讨论
任何不包含如下这些字符的正则表达式都可以简单地匹配其自身:$()*+.?[^{|。如果要在正在编辑的文档中查找是否包含Mary had a little lamb,那么你只需要简单地查找‹Mary●had●a●little●lamb›即可。与你是否选中了文本编辑器中的“正则表达式”复选框并没有关系。
正则表达式之所以拥有巨大的魔力,就是因为有了这12个标点字符,它们被称作是元字符(metacharacter)。如果想要在正则表达式中照字面匹配它们,就需要在它们前面用一个反斜杠来进行转义。因此,正则表达式
\$\(\)\*\+\.\?\[\\\^\{\|
会匹配文本
$()*+.?[\^{|
特别应该注意的是在这个列表中并不包含右方括号]、连字号-和右花括号}。前两个符号只有在它们位于一个没有转义的[之后才成为元字符,而}只有在一个没有转义的{之后才是元字符。在任何时候都没有必要对}进行转义。在[和]之间出现的元字符的转义规则会在实例2.3中加以解释。
对任意其他非字母数字的字符进行转义不会改变你的正则表达式的匹配结果—至少在本书中讲到的所有流派中都不会改变。而对一个字母数字字符进行转义则会给它一个特殊含义,或者出现一个语法错误。
新接触正则表达式的人通常会对看到的每个标点字符进行转义。不要让任何人看出来你是个新手!要明智地选择需要转义的场合(时机)。一大堆不需要的反斜杠会使正则表达式变得难以阅读,特别是当在源代码中把正则表达式作为字符串来引用以至于所有这些反斜杠必须加倍出现的时候。
变体
块转义
当使用的正则流派支持块转义时,我们的解答可以更容易阅读:
The●punctuation●characters●in●the●ASCII●table●are:●↵
\Q!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~\E
正则选项:无
正则流派:Java 6、PCRE、Perl
Perl、PCRE和Java支持使用正则表达式记号‹Q›和‹E›。‹Q›可以消除包括反斜杠在内的所有元字符的特殊含义,直到出现‹E›为止。如果漏掉了‹E›,那么在‹Q›之后直到正则表达式结束之前的所有字符都会被当作字面文本来对待。
使用‹Q...E›的唯一好处是它读起来会比‹...›更容易一些。
虽然Java 4和Java 5都支持这个特性,但是我们却不推荐读者使用它。实现中的bug导致含有‹Q...E›的正则表达式匹配到的内容与你的期望不同,并且与Java 6、PCRE或Perl所匹配的内容不一样。这些bug在Java 6中得到了修正,使之与PCRE和Perl中的结果保持一致。
不区分大小写的匹配
默认情况下,正则表达式是区分大小写的。‹regex›会匹配regex,但是不能匹配Regex、REGEX或者ReGeX。要匹配所有这些形式,就需要打开不区分大小写选项。
在大多数应用程序中,只需要简单地选中或取消一个复选框。在下一章中要讲解的所有编程语言中都提供一个标志或属性,可以用它来标明你的正则表达式不区分大小写。下一章中的实例3.4会讲解如何在源代码中应用本书每个正则表达式解答下列出的正则选项。
ascii
正则选项:不区分大小写
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby
如果无法在正则表达式之外打开不区分大小写选项的话,那么你还可以在正则表达式之内通过使用‹(?i)›模式修饰符(mode modifier)来设置,如‹(?i) regex›。这个选项可以在.NET、Java、PCRE、Perl、Python和Ruby流派中使用。也可以在JavaScript XRegExp库中使用。
(?i)ascii
正则选项:无
正则流派:.NET、Java、XRegExp、PCRE、Perl、Python、Ruby
.NET、Java、PCRE、Perl和Ruby支持局部模式修饰符,这样它只会影响到正则表达式的一部分。例如,‹sensitive(?i)caseless(?-i)sensitive›会匹配sensitiveCASELESS sensitive,但是不能匹配SENSITIVEcaselessSENSITIVE。在正则表达式中‹(?i)›后面的字符不区分大小写,而‹(?-i)›后面的字符重新区分大小写。它们结合在一起就可以像开关一样来使用。