正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为”元字符”)组成的文字模式

普通字符

[ABC] : 匹配 […] 内的所有字符

[^ABC] : 匹配除了 […]中字符的所有字符

[A-Z] : 表示一个区间,匹配 A - Z 范围里的字符

. : 匹配除换行符 \n \r 之外的任何单个字符,相当于[^\r\n]

\s:匹配所有空白字符

\S:匹配所有非空白字符

\w:匹配 字母、数字、下划线等价于[A-Za-z0-9_]

\d: 匹配任意一个阿拉伯数字 等价于[0-9]

非打印字符

字符 描述
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

特殊字符

特别字符 描述
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 [。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “",而 ‘(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 ^。
{ 标记限定符表达式的开始。要匹配 {,请使用 {。
| 指明两项之间的一个选择。要匹配 |,请使用 |。

限定符

* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”* 等价于 **{0,}**。
+ 匹配前面的子表达式一次或多次。例如,zo+ 能匹配 “zo” 以及 “**zoo”**,但不能匹配 “z”+ 等价于 **{1,}**。
? 匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 “do” 、 **”does”**、 “doxy” 中的 “do”“does”? 等价于 **{0,1}**。
{n} n 是一个非负整数。匹配确定的 n 次。例如,o{2} 不能匹配 “Bob” 中的 o,但是能匹配 “food” 中的两个 o
{n,} n 是一个非负整数。至少匹配n 次。例如,o{2,} 不能匹配 “Bob” 中的 o,但能匹配 “foooood” 中的所有 oo{1,} 等价于 o+o{0,} 则等价于 **o***。
{n,m} m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,o{1,3} 将匹配 “fooooood” 中的前三个 oo{0,1} 等价于 **o?**。请注意在逗号和两个数之间不能有空格。

定位符

定位符用来描述字符串或单词的边界,^$ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。

字符 描述
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b 匹配一个单词边界,即字与空格间的位置。
\B 非单词边界匹配。

学习计划

  1. 了解基本的正则表达式的语法
  2. 熟悉常见的正则表达式
  3. 使用正则表达式提取网页html完成一个爬虫项目

基本概念

正则表达式(Regular Expression)缩写为 Regex 或 Regexp,是在正则表达式语法框架内创建的字符串。

可以使用正则表达式来管理数据、执行查找、匹配或编辑等命令

匹配

​ 查找文件列表中,扩展名是pdf的文件

^\w+\.pdf$

​ 基本匹配:查找出文本中的curious

curious

点 . 可以匹配任何字符、包括了特殊字符和空格

​ 字符集 [abc] ,如果一个词中的字符可以是各种字符,我们就将所有的可选字符写进括号[]中

bar ber bir bor bur

b[aeiou]r

否定字符集[^abc]

为了查找下方文本的所有单词(ber 和 bor 除外)

b[^eo]r

字母范围 [a-z] 为了查找指定范围的字母,我们需要将起始字母和结束字母写进 [] 中,中间用连字符 - 分隔。它区分大小写

abcdefghijklmnopqrstuvwxyz

请编写表达式,匹配 e 和 o 之间所有的小写字母,包括它们本身。
[e-o]

数字范围 [0-9] 为了查找指定范围的数字,我们需要在 [] 中输入起始和结束数字,中间用连字符 - 分隔

0123456789

编写表达式,匹配 3 到 6 之间的所有数字,包括它们本身
[3-6]

重复

重复(repetitions) 一些特殊字符用来指定一个字符在文本中重复的次数。它们分别是加号 +、星号 * 和问号 ?

星号 *(Asterisk)在字符后面加上 *,表示一个字符完全不匹配或可以匹配多次

br ber beer

表示字母 e 在下方文本中不出现,只出现 1 次或者并排出现多次
be*r

加号 + (the plus) 表示一个字符可以出现一次或多次,我们将 + 放在它后面

br ber beer

表示 e 在下方文本中出现一次或多次。
be+r

问号 ? (the question mark) 为了表示一个字符是可选的,我们在它后面加一个 ?

color, colour

表示下方文本中的字母 u 是可选的
colou?r

大括号 {} 为了表示一个字符出现的确切次数,我们在该字符的末尾,将它出现的次数写进大括号 {} 中

ber beer beeer beeeer

表示下方文本中的字母 e 只能出现 2 次
be{2}r

表示一个字符至少出现多少次,我们在该字符的末尾,将它至少应出现的次数写进大括号 {} 中,并在数字后面加上逗号 ,

ber beer beeer beeeer

表示下方文本中的字母 e 至少出现 3 次。
be{3,}r

表示一些字符出现的次数在某个数字范围内,我们在该字符的末尾,将它至少和至多出现的次数写进大括号 {} 中,中间用逗号 , 分隔

ber beer beeer beeeer

匹配下方文本中,字母 e 出现 1 至 3 次的单词
be{1,3}r

分组

括号() 对一个表达式进行分组,并用这些分组来引用或执行一些规则 为了给表达式分组,我们需要将文本包裹在 () 中

ha-ha,haa-haa

尝试为下方文本中的 haa 构造分组
(haa)

引用组

单词 ha 和 haa 分组如下。第一组用 \1 来避免重复书写。这里的 1 表示分组的顺序。请在表达式的末尾键入 \2 以引用第二组。

ha-ha,haa-haa

(ha)-\1,(haa)-\2

(?:) 非捕获分组 可以对表达式进行分组,并确保它不被引用捕获

例如,下面有两个分组,但我们用 \1 引用的第一个组实际上是指向第二个组,因为第一个是未被捕获的分组

ha-ha,haa-haa
(?:ha)-ha,(haa)-\1

| 竖线 竖线允许一个表达式包含多个不同的分支。所有分支用 | 分隔。和在字符层面上运作的字符集 [abc] 不同,分支在表达式层面上运作

下面的表达式同时匹配 cat 和 rat。请在末尾添加另一个 |,并输入 dog 以匹配所有单词。

cat rat dog
(c|r)at|dog

转义字符 \ 在书写正则表达式时,我们会用到 { } [ ] / \ + * . $^ | ? 这些特殊字符 。为了匹配这些特殊字符本身,我们需要通过 \ 将它们转义

要匹配文本中的 . 和 *,我们需要在它们前面添加一个 \

(*) Asterisk.
(\*|\.)

插入符 ^ 匹配字符串的开始

Basic Omellette Recipe

1. 3 eggs, beaten
2. 1 tsp sunflower oil
3. 1 tsp butter

若仅查找行首的数字,请在表达式前面加上 ^
^[0-9]

美元符号 $ 匹配字符串的结束

让我们在 html 的后面添加 $,来查找仅在行末出现的 html

https://domain.com/what-is-html.html
https://otherdomain.com/html-elements
https://website.com/html5-features.html

html$

单词字符 \w : 字母、数字、下划线

用表达式 \w 来查找文本中的单词字符。

abcABC123 _.:!?
\w

非单词字符\W : 匹配除了字符、数字、下划线之外的字符

匹配除字母、数字和下划线之外的字符

abcABC123 _.:!?
\W

数字字符 \d : 仅仅用来匹配数字

abcABC123 .:!?

\d

非数字字符 \D :用来匹配非数字字符

abcABC123 .:!?

\D

空白符 \s : 仅匹配空白字符

abcABC123 .:!?

\s

非空白符 \S:仅匹配非空白字符

abcABC123 .:!?

\S

零宽断言

如果我们希望正在写的词语出现在另一个词语之前或之后,我们需要使用「零宽断言」

正向先行断言 (?=)

要匹配文本中的小时值。为了只匹配后面有 PM 的数值,我们需要在表达式后面使用正向先行断言 (?=),并在括号内的 = 后面添加 PM

Date: 4 Aug 3PM
\d+(?=PM)

负向先行断言 (?!)

要在文本中匹配除小时值以外的数字。我们需要在表达式后面使用负向先行断言 (?!),并在括号内的 ! 后面添加 PM,从而只匹配没有 PM 的数值

Date: 4 Aug 3PM
\d+(?!PM)

正向后行断言(?<=)

要匹配文本中的金额数。为了只匹配前面带有 $ 的数字。我们要在表达式前面使用正向后行断言 (?<=),并在括号内的 = 后面添加 \$

Product Code: 1064 Price: $5
(?<=\$)\d+

负向后行断言 (!<=)

要在文本中匹配除价格外的数字。为了只匹配前面没有 $ 的数字,我们要在表达式前用负向后行断言 (?<!),并在括号内的 ! 后面添加 \$

Product Code: 1064 Price: $5
(?<!\$)\d+

标志

标志改变表达式的输出。这就是标志也称为 修饰符 的原因。标志决定表达式是否将文本视作单独的行处理,是否区分大小写,或者是否查找所有匹配项

全局标志 /g 全局标志使表达式选中所有匹配项,如果不启用全局标志,那么表达式只会匹配第一个匹配项

domain.com, test.com, site.com

/ \w+\.com /g

多行标志 /m 正则表达式将所有文本视作一行。但如果我们使用了多行标志,它就会单独处理每一行。

domain.com
test.com
site.com

/ \w+\.com$ /gm

忽略大小写标志 /i 使我们编写的表达式不再大小写敏感

DOMAIN.COM
TEST.COM
SITE.COM

/ \w+\.com$ /gmi

匹配规则

贪婪匹配 :正则表达式默认执行贪婪匹配。这意味着匹配内容会尽可能长

下面的示例,它匹配任何以 r 结尾的字符串,以及前面带有该字符串的文本,但它不会在第一个 r 处停止匹配

ber beer beeer beeeer
.*r

懒惰匹配: 与贪婪匹配不同,懒惰匹配在第一次匹配时停止

下面的例子中,在 * 之后添加 ?,将查找以 r 结尾且前面带有任意字符的第一个匹配项。这意味着本次匹配将会在第一个字母 r 处停止。

ber beer beeer beeeer
.*?r

实际使用

匹配html文件中所有<img> 标签中的src属性

(?<=img.*src=")[\w:/\.?=\\:;&]+(?=")