正则表达式
Micbael·Fitzgerald 人民邮电出版社
http://tool.chinaz.com/regex/
第 1 章 什么是正则表达式
正则表达式有助于找到文本字符串中的各种模式。更确切地说,正则表达式是经过专门编写的文本字符串,用来匹配字符串(尤其是文件内字符串)集合中符合该模式的所有字符串。
正则表达式是描述一组字符串特征的模式,用来匹配特定的字符串。
707-827-7019这种正则表达式是用 字符串字面值 (string literal)
来匹配目标字符串的。
字符串字面值: 字面上看起来是什么就是什么。
正则表达式将方括号视为特殊的 元字符(metacharacter)
,因此方括号不参与匹配。
元字符: 在正则表达式中有特殊含义的字符,也是保留字符。
[0-9]这种形式的正则表达式称做 字符组(charactercla ss)
,有时也叫 字符集(characterset)
。
可以对数字的范围进行进一步限定。用更具体的一组数字也能得到同样的结果,比如[12789],这个字符组只会匹配列出的数字,即1、2、7、8、9。\d
可以匹配任意阿拉伯数字。
这种正则表达式叫做 字符组简写式(character shorthand)
,也叫 转移字符(character escape)
。
可以使用以下表达式来匹配电话号码中的任意数字:\d\d\d-\d\d\d-\d\d\d\d除了和上面表达式一样,使用连字符本身(-)来匹配连字符之外,也可以用转义的大写D(\D)。它匹配任何一个非数字字符。\d\d\d\D\d\d\d\D\d\d\d\d
还可以用点号(.)来匹配连字符\d\d\d.\d\d\d.\d\d\d\d点号(英文句号)是一个通配符,可以匹配任意字符(但某些情况下不能匹配行起始符)。它也可以匹配百分号(%)或竖线(|)\d\d\d%\d\d\d%\d\d\d\d\d\d\d|\d\d\d|\d\d\d\d
本节我们使用捕获分组(capturing group)来匹配电话号码中的某一部分。然后使用后向引用(backreference)对分组中的内容进行引用。要创建捕获分组,先将一个\d放在一对圆括号中,这样就将它放入了一个分组中,后面可以用\1来对捕获的内容进行后向引用:(\d)\d\1\1对括号内分组捕获的内容进行了反向引用。这个正则表达式匹配的是区号707。
-
(\d)匹配第一个数字并将其捕获(数字7)
-
\d匹配第二个数字(数字0)但没有捕获,因为没有括号
-
\1对捕获的数字进行反向引用(数字7)
707-827-7019(\d)0\1\D\d\d\1\D\1\d\d\d\d{3}-?\d{3}-?\d{4}花括号中的数字表示待查找的数字出现的次数。包含数字的花括号是一种量词(quantifier)。花括号本身用做元字符。
问号是另一种量词,在以上表达式中表示连字符是可选的。也就是说,连字符可以不出现或只出现一次。还有其他的量词,例如加号(+)表示“一个或多个”,星号(*)表示“零个或多个”使用量词能让正则表达式变得更简洁:
(\d{3,4}[.-]?)+
-
左圆括号 ( 为捕获分组的起始符
-
反斜杠 \ 为字符组简写式的起始符(对之后的字符进行转义)
-
字符d为字符组简写式的结束符(d匹配0到9范围内的任意数字),
-
左花括号 { 为量词起始符;
-
数字3为匹配的最小数量;
-
逗号 , 隔开不同的数量;
-
数字4为匹配的最大数量;
-
右花括号 } 为量词的结束符;
-
左方括号 [ 为字符组的起始符;
-
点号 . (匹配点号本身);
-
连字符 - 匹配连字符的本身;
-
右方括号 ] 为字符组的结束符;
-
问号 ? 表示量词“零个或一个“;
-
右圆括号 ) 为捕获分组的结束符;
-
加号 + 表示量词“一个或多个“。
这个表达式能用但不完全对,因为它只能匹配3位或4位的数字,而不管是否符合电话号码的格式。改进:(\d{3}[.-]?){2}\d{4}这个表达式匹配的字符串是连续两个无括号的三位数字,每三位数字后可以带连字符也可以不带,最后是一个四位数字。
括选文字符最后这个正则表达式表示第一个3位数字可以带也可以不带括号,即区号是可选的:
^(\(\d{3}\)|^\d{3}[.-]?)?\d{3}[.-]?\d{4}$
-
出现在正则表达式起始位置或者竖线(|)之后的脱字符^,表示电话号码会出现在一行的起始位置;
-
左括号 ( 为捕获分组的起始符;
-
(表示左括号本身;
-
\d匹配一位数字,
-
\d之后的{3}是量词,表示匹配三位数字;
-
)匹配右括号本身;
-
竖线符|表示选择,也就是从多个可选项中选择一个,换句话说,它表示“匹配一个不带括号的区号或一个带括号的区号“;
-
脱字符 ^ 匹配行起始位置;
-
\d匹配一位数字,
-
{3}是表示匹配三位数字的量词;
-
[.-]? 匹配一个可选的点号或连字符;
-
右括号 ) 为捕获分组的结束符,
-
问号 ? 表示分组可选,即分组中的前缓可有可无;
-
\d匹配一位数字;
-
{3}表示匹配三位数字的量词;
-
[.-]?匹配另一个可选的点号或连字符;
-
\d匹配一位数字;
-
{4}是表示匹配四位数字的量词:
-
美元符$匹配行结束位置。
这个表达式最终匹配十位的北美电话号码,而且括号、连字符或者点号都是可选的。
以上正则表达式中的捕获分组并不是必需的。分组是必要的,但是捕获不需要,更好的方法是使用非捕获分组。(之后才讨论)
为什么有那么多编写正则表达式的方法?一个原因是正则表达式具有可组合性(composability)。
第 2 章 简单的模式匹配
正则表达式唯一的用途就是在文本中匹配和寻找模式,模式可以简单也可以复杂。
2.1 匹配字符串字面值
正则表达式最为直接和明显的功能就是用一个或多个字符字面值来匹配字符串。
2.2 匹配数字
\d 和 [0-9]效果是一样的字符组[0-9]表示范围,这意味着它会匹配0至9范围内的数字。数字的字符组简写式\d更为简短,但却没有字符组强大、灵活。在无法使用\d时(不是所有情况下都支持这种方式),或者想匹配特定数字时,就需要使用字符组,合适的时候可以使用\d,因为它更简短。
2.3 匹配非数字字符
通常可以将简写式取反,取反的结果就是排除。比如,要匹配非数字字符,可使用包含以下大写字母D的简写式:\D[^0-9][^\d]
2.4 匹配单词和非单词字符
\w\D与\w的区别是\D会匹配空格、标点符号(引号、连字符、反斜杠、方括号)等字符,而\w却不会,它只匹配字母、数字和下划线。在英语环境中,与\w匹配相同内容的字符组为:[_a-zA-Z0-9]现在用大写字母W匹配非单词字符:\W相当于[^_a-zA-Z0-9]
字符简写式 | 描述 |
---|---|
\a | 报警符 |
[\b] | 退格字符 |
\c x | 控制字符 |
\d | 数字字符 |
\D | 非数字字符 |
\o xxx | 字符的八进制 |
\w | 单词字符 |
\W | 非单词字符 |
\0 | 空字符 |
\x xx | 字符的十六进制值 |
\u xxx | 字符的Unicode值 |
2.5 匹配空字符
\s以下字符组与\s匹配的内容相同:[ \t\n\r]也就是,它会匹配:
-
空格
-
制表符(\t)
-
换行符(\n)
-
回车符(\r)
要匹配非空白字符:\S这个简写式匹配除空白符之外的所有符号。它匹配字符组:[^ \t\n\r]或者[^\s]
匹配各种空白符的简写式
字符简写式 | 描述 |
---|---|
\f | 换页符 |
\h | 水平空白符 |
\H | 非水平空白符 |
\n | 换行符 |
\r | 回车符 |
\s | 空白符 |
\S | 非空白符 |
\t | 水平制表符 |
\v | 垂直制表符 |
\V | 非垂直制表符 |
2.6 再谈匹配任意字符
用正则表达式匹配任意字符的一种方法就是使用点号(U+002E)。点号可以匹配除行结束符之外的所有字符,个别情况除外。要匹配 THE RIME
整个短语,则可使用八个点号:........但这种方法太麻烦,所以推荐用量词:.{8}这个表达式能匹配前两个单词以及它们之间的空格,但只是粗略的匹配。(所有字符都可匹配到)
下面是匹配单词的边界和字母的开始和结束位置。\bA.{5}T\b这个表达式有更强的特指性(specificity),它匹配单词ANCYENT,也就是ancient的旧式拼写形式。
-
简写式 \b 匹配单词边界,不消耗任何字符
-
字符 A 和 T 限定了字符序列的首尾字母
-
.{5}匹配任意五个字符
-
简写式 \b 匹配单词的另一个边界
\b\w{7}\b.*它就相当于[^\n]或[^\n\r]类似的,点号也可以与表示“一个或多个”的量词(+)连用:.+这涉及到量词的贪心特性。所谓 “贪心”(greedy),指量词会匹配所有能匹配的字符。
第 3 章 边界
本章的重点是断言。断言是标记边界,但是并不耗用字符。也就是说,字符并不会返回到结果中。断言也被称做 “零宽度断言(zero-width assertion)”。零宽度断言不匹配字符,而是匹配字符串中的位置。其中的一些,比如 ^和$,也叫做 锚位符(anchor)
。边界有以下几种:
-
行或者字符串的起始与结束位置
-
单词边界(两种)
-
主题词的起始与结束位置
-
引用字符串字面值的边界
3.1 行的起始与结束
就像之前看到的那样,要匹配行或字符串的起始要使用脱字符(U+005E):^根据上下文,^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置。而上下文则依赖于应用程序和在应用程序中所使用的选项。如你所知,若要匹配行或字符串的结尾位置要使用美元符:$
^How.*Country\.$
它会匹配以单词How开头的整行。请注意结尾的点号之前有一个反斜杠,它对点号进行转移,这样点号就被解释为字面值。如果不对点号转义,它就会匹配任意字符。如果要匹配作为字面值的点号,则必须将点号转义或者将其放入字符组中。
3.2 单词边界与非单词边界
\b 匹配单词边界\bTHE\b
就像 ^ 和 $一样,\b 是个零宽度断言,表面上它会匹配空格或者是行起始,而实际上它匹配的是个零宽度的不存在的东西。要匹配一个非单词边界。可以:\Be\B
会匹配到小写字母e,而匹配的字母e的两边都是其他字母或者是非单词字符。零宽度断言不会匹配两边的字符,但它会识别文字e的两边是否是非单词边界。
在有些应用程序中,指定单词边界的另一种方法是使用:\<
来指定单词的开头,而使用\>
来指定单词结尾。这是比较旧的语法,在很多最新的正则表达式应用程序中无法使用。但在有些情况下,这种语法就很有用,因为它不会像 \b
那样匹配任意单词边界,而是允许你分别匹配单词的开头或结尾。
第 4 章 选择、分组和后向引用
4.1 选择操作
选择操作可在多个可选模式中匹配一个。(the|The|THE)可以使用一个选项来使分组更简短。借助选项,可以指定查找模式的方法。(?i)让你的模式不再区分大小写。因此原来带选择操作的模式可以简写成:(?i)the
4.2 子模式
多数情况下,提到正则表达式中的子模式(subpattern),就是指分组中的一个或多个分组。子模式就是模式中的模式。多数情况下,子模式中的条件能得到匹配的前提是前面的模式得到匹配,但也有例外。子模式的写法可以有很多种,这里我们主要关注括号中的子模式。
(the|The|THE)有三个子模式。但是这种情况下,匹配第二个子模式不依赖于是否匹配第一个。(最左边的模式会首先匹配。)以下模式中,子模式依赖于前面的模式:(t|T)h(e|eir)通俗地讲,这个模式会匹配字面值t或T,然后是一个h,接下来就是一个e或者是eir。相应地,这个模式会匹配以下所有情况:
-
the
-
The
-
their
-
Their
以上情况中,第二个子模式(e|eir)依赖于第一个子模式(tT)。括号对于子模式不是必需的。\b[tT]h[ceinry]*\b这个模式会匹配the或The还有thee,thy以及thence等单词。两个单词边界(\b)表示该模式只匹配整个单词,而不会匹配单词中的某几个字母。
-
\b匹配单词起始边界
-
[tT]是字符组,它匹配小写字母t或者大写字母T。可以将其看作是第一个子模式。
-
然后匹配(或尝试匹配)小写字母h
-
第二个也就是最后一个子模式也表示为字符组[ceinry],其后用量词*表示零个或多个。
-
最后,该模式以另外一个\b结束
4.3 捕获分组和向后引用
当一个模式的全部或者部分内容由一对括号分组时,它就对内容进行捕获并临时存储于内存中。可以通过后向引用重用捕获的内容,形式为:\1或$1
这里 \1
或 $1
引用的是第一个捕获的分组,而\2或$2引用第二个捕获的分组,以此类推。
4.4 非捕获分组
还有一种分组是非捕获分组(Non-Capturing Group)。非捕获分组不会将其内容存储在内存中。在你并不想引用分组的时候,可以使用它。由于不存储内容,非捕获分组就会带来较高的性能,而运行本书的简单示例很难察觉到性能的提升。(?:the|The|THE)或者可以这样做:(?:(?i)the)不过,下面这种写法最值得推荐:(?i:the)该选项i可以放在问好和冒号之间
原子分组
另一种非捕获分组时原子分组(atomic group)。如果你使用的正则表达式引擎进行回溯操作,这种分组就可以将回溯操作关闭,但它只针对原子分组内的部分,而不针对整个正则表达式。(?>the)正则表达式处理过程缓慢的一个因素就是回溯操作。其原因就是回溯操作会尝试每一种可能性,这会消耗时间和计算资源。有时它会占用大量时间。回溯有可能产生巨大的负面效应,这被称为灾难性回溯。原子分组可以关闭正则表达式的部分回溯操作。
第 5 章 字符组
字符组有时也被称为方括号表达式(bracketed expression)。字符组有助于匹配特定字符或者特定的字符序列。它们可以像字符简写式那样代表一大批字符。比如,\d匹配的字符与[0-9]所匹配的字符一样。但字符组更有针对性,因此用途比简写式更广。想匹配10-19的偶数:\b1\b同理,也能想到用下面的表达式查找0-99的偶数:\b[24680]\b|\b1-9\b要想创建一个匹配十六进制数的字符组怎么做:[a-fA-F0-9]还可以在字符组内使用简写式。例如,要匹配空格和单词字符,可以创建这样一个字符组:[\w\s]它等同于[_a-zA-Z \t\n\r]
5.1 字符组取反
脱字符(^)的意义就是:不,我不想匹配这些字符。(脱字符必须出现在起始位置)
5.2 并集与差集
字符组可以像集合那样操作。事实上,字符组的另一个名称就是字符集(character set)。(并不是所有的实现程序都支持这项功能)[0-3[6-9]匹配差集(实质上就是减操作):[a-z&&m-r]这匹配a到z之间的字符,但其中m到r之间的字符除外。
第 6 章 量词
6.1 贪心、懒惰和占有
贪心: 量词自身是贪心的。贪心的量词会首先匹配整个字符串。尝试匹配时,它会选定尽可能多的内容,也就是整个输入。量词首次尝试匹配整个字符串,如果失败则回退一个字符后再次尝试。这个过程叫做回溯(backtracking)。它会每次回退一个字符,直到找到匹配的内容或者没有字符可尝试为止。此外,它还记录所有的行为,因此相较另两种方式它对资源的消耗最大。
懒惰: (有时也说勉强)。它从目标的起始位置开始尝试寻找匹配,每次检查字符串的一个字符,寻找它要匹配的内容。最后,它会尝试匹配整个字符串。要使一个量词成为懒惰的,必须在普通量词后添加一个问号(?)。它每次只“吃”一点。
占有量词: 会覆盖整个目标然后尝试寻找匹配内容,但它只尝试一次,不会回溯,占有量词就是在普通量词之后添加一个加号(+)。它不“咀嚼”而是直接“吞咽”,然后才想知道“吃”的是什么。
6.2 用*、+和?进行匹配
.* 它将会以贪心的方式匹配主文本中的所有字符。(数字)。要匹配一个或多个9,尝试:9+会寻找至少一个9,而*会寻找零个或多个9.要匹配零次或一次,可使用:9?
6.3 匹配特定次数
使用花括号可以限制某个模式在某个范围内匹配的次数,未经修饰的量词就是贪心量词。7{1}会匹配第一个出现的7.要匹配一个或多个数字7,只要加一个逗号即可:7{1,}
7+和7{1,}本质上是一样的。7*和7{0,}也是相同的。
换可以匹配m到n次7{3,5}
语法 | 描述 |
---|---|
{n} | 精确匹配n次 |
{n,} | 匹配n次或更多次 |
{m,n} | 匹配m至n次 |
{0,1} | 与?相同(零次或一次) |
{1,} | 与+相同(一次或更多) |
{0,} | 与*相同(零次或更多) |
6.4 懒惰量词
懒惰的基本特性就是匹配尽可能少的字符——包括0次。5*?不会匹配任何内容,因为可以选择匹配最少的次数——0次。5+?最少匹配一个,所以它匹配一个。5{2,5}?只匹配了两个5,而不像贪心量词那样匹配5个。
语法 | 描述 |
---|---|
?? | 懒惰匹配零次或一次(可选) |
+? | 懒惰匹配一次或多次 |
*? | 懒惰匹配零次或多次 |
{n}? | 懒惰匹配n次 |
{n,}? | 懒惰匹配n次或多次 |
{m,n}? | 懒惰匹配m至n次 |
6.5 占有量词
占有式匹配很像贪心式匹配,它会选定尽可能多的内容。但与贪心式匹配不同的是它不进行回溯。它不会放弃所找到的内容,它很自私,这也是把它称为占有式(possessive)的原因。它仅仅“抱”住自己所选的内容,一点也不放弃。但占有量词的优点是速度快,因为无需回溯。当然,匹配失败的话也很快。
先尝试匹配以零开头的多个零,然后再匹配以零结尾的多个零。0.*+所有的零都被标亮了。存在一个匹配。占有式的匹配看起来和贪心式的匹配是一样的,但没有回溯。
.*+0没有匹配——原因就是没有回溯。它一下就选定了所有的输入,不再回过来查看。如果将加号去掉,它会找到所有的0,因为它变回贪心式匹配了。.*0当知道文本中的内容时,就知道在哪里可以找到匹配,这时应该使用占有量词。不在乎它是否会选定所有内容。占有式匹配有助于提高匹配的性能。
语法 | 描述 |
---|---|
?+ | 占有式匹配零次或一次(可选) |
++ | 占有式匹配一次或多次 |
*+ | 占有式匹配零次或多次 |
{n}+ | 占有式匹配n次 |
{n,}+ | 占有式匹配n次或更多次 |
{m,n}+ | 占有式匹配m至n次 |
环视
环视是一种 非捕获分组,它根据某个模式之前或之后的内容匹配其他模式。环视也称为 零宽度断言。
环视包括:
-
正前瞻
-
反前瞻
-
正后顾
-
反后顾
7.1 正前瞻
假设要匹配单词ancyent,且要求紧随其后的单词是marinere。(?i)ancyent (?=marinere)由于我们使用了不区分大小写的选项(?i),就不必担心模式中用的大小写形式了。现在就是在每一行中寻找后跟marinere的单词ancyent。只有模式的第一部分(ancyent)被标亮,(marinere)不会标亮。
7.2 反前瞻
反前瞻是对正前瞻的取反操作。这意味着要匹配某个模式时,需要在它后面找不到含有给定前瞻模式的内容。(?i)ancynet (?!marinere)
只有一个字符发生了变化:正前瞻的等号(=)变为反前瞻的感叹号(!)。
7.3 正后顾
(?i)(?<=ancyent) marinere
正后顾使用小于号(<),提醒你后顾是哪个方向。被标亮的是marinere而不是ancyent。
7.4 反后顾
反后顾会查看某个模式在从左至右的文本流的后面没有出现。同样,它有一个小于号(<),提醒后顾的是哪个方向。(?1)(?<!ancyent) marinere
^\(?(?:\d{3})\)?[-.]?(?:\d{3})[-.]?(?:\d{4})$
-
^是判断一行或者主题词开头的零宽度断言
-
(?是一个字面左括号,但它是可选的(?)
-
(?:\d{3})是一个匹配连续三位数字的非捕获分组
-
)?是可选的右括号
-
[-.]?允许有可选的连字符或者句点(点号)
-
(?:\d{3})是另一个匹配连续三位数字的非捕获分组
-
(-.)?再次允许有可选的连字符或者句号(点号)
-
(?:\d{4})是匹配连续四位数字的非捕获分组
-
$匹配一行或主题词的结尾
匹配电子邮件地址的正则表达式:^({\w-.!#$%&'*+-/=?^_
{|}~]+)@((?:\w+.)+)(?:[a-zA-Z]{2,4})$`
--------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- ---------------------------------------------------
2
字符组 : [字符组] 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示 字符分为很多类,比如数字、字母、标点等等。 假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。
正则 |
待匹配字符 |
匹配 |
说明 |
[0123456789] |
8 |
True |
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符 |
[0123456789] |
a |
False |
由于字符组中没有"a"字符,所以不能匹配 |
[0-9] |
7 |
True |
也可以用-表示范围,[0-9]就和[0123456789]是一个意思 |
[a-z] |
s |
True |
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示 |
[A-Z] |
B |
True |
[A-Z]就表示所有的大写字母 |
[0-9a-fA-F] |
e |
True |
可以匹配数字,大小写形式的a~f,用来验证十六进制字符 |
字符:
元字符 |
匹配内容 |
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
\b | 匹配一个单词的结尾 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结尾 |
\W |
匹配非字母或数字或下划线 |
\D |
匹配非数字 |
\S |
匹配非空白符 |
a|b |
匹配字符a或字符b |
() |
匹配括号内的表达式,也表示一个组 |
[...] |
匹配字符组中的字符 |
[^...] |
匹配除了字符组中字符的所有字符 |
量词:
量词 |
用法说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
. ^ $
正则 | 待匹配字符 | 匹配 结果 |
说明 |
海. | 海燕海娇海东 | 海燕海娇海东 | 匹配所有"海."的字符 |
^海. | 海燕海娇海东 | 海燕 | 只从开头匹配"海." |
海.$ | 海燕海娇海东 | 海东 | 只匹配结尾的"海.$" |
* + ? { }
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李.? | 李杰和李莲英和李二棍子 |
李杰 |
?表示重复零次或一次,即只匹配"李"后面一个任意字符 |
李.* | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
*表示重复零次或多次,即匹配"李"后面0或多个任意字符 |
李.+ | 李杰和李莲英和李二棍子 | 李杰和李莲英和李二棍子 |
+表示重复一次或多次,即只匹配"李"后面1个或多个任意字符 |
李.{1,2} | 李杰和李莲英和李二棍子 |
李杰和 |
{1,2}匹配1到2次任意字符 |
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李.*? | 李杰和李莲英和李二棍子 | 李 李 李 |
惰性匹配 |
字符集[][^]
正则 | 待匹配字符 | 匹配 结果 |
说明 |
李[杰莲英二棍子]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配"李"字后面[杰莲英二棍子]的字符任意次 |
李[^和]* | 李杰和李莲英和李二棍子 |
李杰 |
表示匹配一个不是"和"的字符任意次 |
[\d] | 456bdha3 |
4 |
表示匹配任意一个数字,匹配到4个结果 |
[\d]+ | 456bdha3 |
456 |
表示匹配任意个数字,匹配到2个结果 |
分组 ()与 或 |[^]
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:
正则 | 待匹配字符 | 匹配 结果 |
说明 |
^[1-9]\d{13,16}[0-9x]$ | 110101198001017032 |
110101198001017032 |
表示可以匹配一个正确的身份证号 |
^[1-9]\d{13,16}[0-9x]$ | 1101011980010170 |
1101011980010170 |
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 |
^[1-9]\d{14}(\d{2}[0-9x])?$ | 1101011980010170 |
False |
现在不会匹配错误的身份证号了 |
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ | 110105199812067023 |
110105199812067023 |
表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14} |
转义符 \
在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对"\"进行转义,变成'\\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\n",字符串中要写成'\\n',那么正则里就要写成"\\\\n",这样就太麻烦了。这个时候我们就用到了r'\n'这个概念,此时的正则是r'\\n'就可以了。
正则 | 待匹配字符 | 匹配 结果 |
说明 |
\n | \n | False |
因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配 |
\\n | \n | True |
转义\之后变成\\,即可匹配 |
"\\\\n" | '\\n' | True |
如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次 |
r'\\n' | r'\n' | True |
在字符串之前加r,让整个字符串不转义 |
贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 | 待匹配字符 | 匹配 结果 |
说明 |
<.*> |
<script>...<script> |
<script>...<script> |
默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> | r'\d' |
<script> |
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复 +? 重复1次或更多次,但尽可能少重复 ?? 重复0次或1次,但尽可能少重复 {n,m}? 重复n到m次,但尽可能少重复 {n,}? 重复n次以上,但尽可能少重复
.*?的用法
. 是任意字符 * 是取 0 至 无限长度 ? 是非贪婪模式。 何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在: .*?x 就是取前面任意长度的字符,直到一个x出现