4.2 正则表达式入门

正则表达式是基于样式匹配的文本处理技术的关键所在。想要在编写文本处理工具方面驾轻就熟,你就必须对正则表达式有一个基本的理解。正则表达式是一种用于文本匹配的形式小巧、具有高度针对性的编程语言。只依靠通配符技术,能够匹配的文本范围相当有限。这则攻略将对基础的正则表达式进行讲解。

4.2.1 预备知识

正则表达式是用于绝大多数文本处理工具的一种语言。因此你完全可以把在这里学习到的技术应用到其他攻略中。[a-z0-9_]+@[a-z0-9]+.[a-z]+就是一个能够匹配电子邮件地址的正则表达式。

它看起来是不是很古怪?别担心,一旦你理解了相关的概念,它其实相当简单。

4.2.2 实战演练

本节将会让你简单了解一下正则表达式、POSIX字符类(POSIX character class)以及元字符(meta character)。

先来看一看正则表达式的基本组成部分,如表4-1所示。

表 4-1

正则表达式 描  述 示  例
^ 行起始标记 ^tux 匹配以tux起始的行
$ 行尾标记 tux$ 匹配以tux结尾的行
. 匹配任意一个字符 Hack.匹配Hackl和Hacki,但是不能匹配Hackl2和Hackil,它只能匹配单个字符
[] 匹配包含在 [字符] 之中的任意一个字符 coo[kl] 匹配cook或cool
[^] 匹配除 [^字符] 之外的任意一个字符 9[^01] 匹配92、93,但是不匹配91或90
[-] 匹配 [] 中指定范围内的任意一个字符 [1-5] 匹配从1~5的任意一个数字
? 匹配之前的项1次或0次 colou?r 匹配color或colour,但是不能匹配colouur
+ 匹配之前的项1次或多次 Rollno-9+ 匹配Rollno-99、Rollno-9,但是不能匹配Rollno-
* 匹配之前的项0次或多次 co*l 匹配cl、col、coool等
() 创建一个用于匹配的子串 ma(tri)?x 匹配max或maxtrix
{n} 匹配之前的项n次 [0-9]{3} 匹配任意一个三位数,[0-9]{3}可以扩展为[0-9][0-9][0-9]
{n,} 之前的项至少需要匹配n次 [0-9]{2,} 匹配任意一个两位或更多位的数字
{n,m} 指定之前的项所必需匹配的最小次数和最大次数 [0-9]{2,5} 匹配从两位数到五位数之间的任意一个数字
| 交替——匹配 | 两边的任意一项 Oct (1st | 2nd) 匹配Oct 1stOct 2nd
\ 转义符可以将上面介绍的特殊字符进行转义 a.b匹配a.b,但不能匹配ajb。通过在 . 之间加上前缀 \ ,从而忽略了 . 的特殊意义

POSIX字符类是一个形如 [:…:] 的特殊元序列(meta sequence),它可以用于匹配特定的字符范围。POSIX字符类如表4-2所示。

表 4-2

正则表达式 描  述 示  例
[:alnum:] 字母与数字字符 [[:alnum:]]+
[:alpha:] 字母字符(包括大写字母与小写字母) [[:alpha:]]{4}
[:blank:] 空格与制表符 [[:blank:]]*
[:digit:] 数字字符 [[:digit:]]?
[:lower:] 小写字母 [[:lower:]]{5,}
[:upper:] 大写字母 ([[:upper:]]+)?
[:punct:] 标点符号 [[:punct:]]
[:space:] 包括换行符、回车等在内的所有空白字符 [[:space:]]+

元字符是一种Perl风格的正则表达式,只有一部分文本处理工具支持它,并不是所有的工具都支持表4-3中所列的字符,但是之前介绍的正则表达式和字符类都是被广泛支持的。

表 4-3

正则表达式 描  述 示  例
\b 单词边界 \bcool\b匹配cool,但不匹配coolant
\B 非单词边界 cool\B匹配coolant,但不匹配cool
\d 单个数字字符 b\db匹配b2b,但不匹配bcb
\D 单个非数字字符 b\Db匹配bcb,但不匹配b2b
\w 单个单词字符(字母、数字与 _ ) \w匹配1或a,但不匹配 &
\W 单个非单词字符 \W匹配&,但不匹配1或a
\n 换行符 \n匹配一个新行
\s 单个空白字符 x\sx匹配x x,但不匹配xx
\S 单个非空白字符 \x\S\x匹配xkx,但不匹配xx
\r 回车 \r匹配回车

4.2.3 工作原理

在4.2.2节中看到的表格是正则表达式的关键元素表。在表中挑选恰当的正则表达式,我们就能够根据需要构建出适合的正则表达式来匹配文本。正则表达式是一种用于文本匹配的通用语言。因此我们在这则攻略中不会介绍任何工具,而是把这个任务放到本章的其他攻略中。

来看几个文本匹配的例子。

  • 为了匹配给定文本中的所有单词,可以使用下面的正则表达式:
  1. ( ?[a-zA-Z]+ ?)

?”用于匹配单词前后可能出现的空格。[a-zA-Z]+代表一个或多个字母(a~z和A~Z)。

  • 为了匹配一个IP地址,可以使用下面的正则表达式:
  1. [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}

或者

  1. [[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}

我们知道IP地址通常的书写形式是192.168.0.2,它是由点号分割的4个整数(每一个整数的取值范围从0到255)。

[0-9][:digit:]匹配数字0~9。{1,3}匹配1到3个数字,.匹配"."

4.2.4 补充内容

下面就看一看如何在正则表达式中指定某些字符的特殊含义。

处理特殊字符

正则表达式用$^.*+{以及}等作为特殊字符。但是如果我们希望将这些字符作为非特殊字符(表示普通字面含义的字符)来使用的话,应该怎么做呢?来看一个例子。

正则表达式:[a-z]*.[0-9]

那么,它是什么意思?

它可以匹配0个或多个a-z,接任意单个字符(.),再接[0-9]中的任意一个字符,所以它能够匹配 abcdeO9

它也可以理解成:匹配[a-z]中任意一个字符,接单个字符*,再接单个字符.(点号),最后接一个数字,所以它能够匹配x*.8

为了避免这种理解上的混乱,我们可以在字符前面放上一个“\”(这种做法称为“对字符进行转义”)。对于像 * 这种具有多种含义的字符,可以在前面加上“\”,使其具备或丧失某些特殊的含义。至于转义后字符的意义是否具备特殊的含义,则取决于你所使用的工具。