目录

  1. 概述
  2. 正则表达式语法
  3. 正则表达式的字符
    1. 普通字符
    2. 非打印字符
    3. 特殊字符
    4. 限定符
    5. 定位符
    6. 选择符
  4. 反向引用
  5. 正则表达式的修饰符
  6. 正则表达式的元字符
  7. 正则表达式运算符优先级
  8. 正则表达式的匹配规则
    1. 基本模式匹配
    2. 字符簇匹配
    3. 重复出现匹配
  9. 附录

概述

❓什么是正则表达式?

  • 正则表达式(Regular Expression)是一种文本模式,由普通字符(例如,a 到 z 之间的字母)和特殊字符(称为元字符)组成
  • 通过正则表达式可以准确匹配到一系列符合你预期要求的字符串

❓为什么使用正则表达式?

  • 典型的搜索替换操作要求提供与预期的搜索结果匹配的确切文本,如:经常使用的搜索方式就属于典型搜索,通过键入ctrl+f快捷键后,需要输入确切的文本才能匹配到准确的结果,但是如果想要模糊查询是困难的,而这正是正则表达式的强项
  • 正则表达式可以测试字符串内的模式,如:可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式,这也称为数据验证
  • 正则表达式可以替换文本,可以使用正则表达式来识别文档中的特定文本,完全删除该文件或使用其他文本来替换它
  • 正则表达式可以基于模式匹配从字符串中提取子字符串,查找文档内或输入域内特定的文本

📓简而言之,使用正则表达式能够精确的帮助你从复杂的文本中检索出预想的结果,简化文档查找替换工作,是开发人员的一大利器,并且几乎各大主流编程语言都做到了支持正则表达式

正则表达式语法

学习正则表达式首先从一个问题开始,假设你拥有一个随机字符串的文件,你需要从这个文件中找出以pineapple开头并且以man结尾的字符串?

✨构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式,正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

正则表达式是由普通字符以及特殊字符组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模版,将某个字符模式与所搜索的字符串进行匹配

正则表达式的字符

📖正则表达式中最重要的就是字符,

普通字符

✨普通字符包括没有显式指定为元字符的所有可打印和不可打印字符,这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号

字符含义
ABCD… … Z表示正常的英文大写字母
abcd… … z表示正常的英文小写字母

非打印字符

非打印字符也可以是正则表达式的组成部分,下表列出了表示非打印字符的转义序列:

字符描述
\n匹配一个换行符
\r匹配一个回车符
\s匹配任何空白字符,包括空格、制表符、换页符等等
\S匹配任何非空白字符
\t匹配一个制表符

特殊字符

特殊字符,表示一些有特殊含义的字符, 也称之为元字符。若要匹配这些特殊字符,必须首先使用字符转义,即将反斜杠字符\ 放在它们前面,下表列出了正则表达式中的特殊字符:

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

限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配,有 *+?{n}{n,}{n,m} 共 6 种,正则表达式的限定符如下:

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

🎶*+限定符都是贪婪的,它们都会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配

定位符

定位符能够将正则表达式固定到行首或行尾,定位符用来描述字符串或单词的边界,^$分别指定字符串的开始与结束,\b描述单词的前或后边界,B表示非单词边界

正则表达式的定位符有:

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

🎶 不能将限定符与定位符在一起使用,由于在紧靠换行或者单词边界的前面或后面不能有一个以上位置,因此不允许诸如 ^* 之类的表达式。若要匹配一行文本开始处的文本,请在正则表达式的开始使用 ^ 字符;若要匹配一行文本的结束处的文本,请在正则表达式的结束处使用 $ 字符

选择符

用圆括号()将所有选择项括起来,相邻的选择项之间用|分隔,()表示捕获分组,()会把每个分组里的匹配的值保存起来, 多个匹配值可以通过数字 n 来查看(n 是一个数字,表示第 n 个捕获组的内容)

使用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?: 放在第一个选项前来消除这种副作用。其中?:是非捕获元之一,还有两个非捕获元是?=?!,这两个还有更多的含义,前者表示正向预查,在任何开始匹配圆括号的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式的位置来匹配搜索字符串。

正则表达式含义
exp1(?=exp2)查找 exp2 前面的 exp1
(?<=exp2)exp1查找 exp2 后面的 exp1
exp1(?!exp2)查找后面不是 exp2 的 exp1
(?<!exp2)exp1查找前面不是 exp2 的 exp1

更多内容可以参考:正则表达式的先行断言(lookahead)和后行断言(lookbehind)

反向引用

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 \n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

可以使用非捕获元字符 ?:?=?! 来重写捕获,忽略对相关匹配的保存。

正则表达式的修饰符

✨正则表达式的修饰符,也称为标记,用于指定额外的匹配策略,标记不写在正则表达式里,标记位于表达式之外,格式如下

1
/Pattern/flags

下表列出了正则表达式常用的修饰符:

修饰符含义描述
iignore将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
gglobal查找所有的匹配项。
mmulti line使边界字符 ^$ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s特殊字符圆点 . 中包含换行符 \n默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

正则表达式的元字符

| 字符 | 描述 |
| :----------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | — | — | --------------------------------------------------------------------------------------------- |
| \ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,‘n’ 匹配字符 “n”。‘\n’ 匹配一个换行符。序列 ‘\’ 匹配 “” 而 “(” 则匹配 “(”。 |
| ^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 |
| $ | 匹配输入字符串的结束位置。如果设置了 RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。 |
| * | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 |
| + | 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 |
| ? | 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。 |
| {n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
| {n,} | n 是一个非负整数。至少匹配 n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。 |
| {n,m} | m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 |
| ? | 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’。 |
| . | 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像"(.|\n)“的模式。 |
| (pattern) | 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在 VBScript 中使用 SubMatches 集合,在 JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 ‘(’ 或 ‘)’。 |
| (?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 ‘industry|industries’ 更简略的表达式。 |
| (?=pattern) | 正向肯定预查(look ahead positive assert),在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
| (?!pattern) | 正向否定预查(negative assert),在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
| (?<=pattern) | 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95 | 98 | NT | 2000)Windows"能匹配"2000Windows"中的"Windows”,但不能匹配"3.1Windows"中的"Windows"。 |
| (?<!pattern) | 反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95 | 98 | NT | 2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。 |
| x|y | 匹配 x 或 y。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。 |
| [xyz] | 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 |
| [^xyz] | 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’、‘l’、‘i’、‘n’。 |
| [a-z] | 字符范围。匹配指定范围内的任意字符。例如,‘[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 |
| [^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,‘[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。 |
| \b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
| \B | 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
| \cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。 |
| \d | 匹配一个数字字符。等价于 [0-9]。 |
| \D | 匹配一个非数字字符。等价于 [^0-9]。 |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
| \s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
| \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
| \t | 匹配一个制表符。等价于 \x09 和 \cI。 |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
| \w | 匹配字母、数字、下划线。等价于’[A-Za-z0-9_]‘。 |
| \W | 匹配非字母、数字、下划线。等价于 ‘[^a-za-z0-9_]’。 |
| \xn | 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,’\x41’ 匹配 “A”。‘\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。 |
| \num | 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,‘(.)\1’ 匹配两个连续的相同字符。 |
| \n | 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
| \nm | 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 |
| \nml | 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 |
| \un | 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?) |

正则表达式运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似,相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到在最低说明了各种正则表达式运算符到优先级顺序

运算符描述
\转义符
(), (?😃, (?=), []圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}限定符
^, $, \任何元字符、任何字符定位点和序列(即:位置和顺序)
|替换,“或"操作 字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food”。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。

正则表达式的匹配规则

首先从最基本的开始,模式是正则表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂

基本模式匹配

基本模式匹配的正则表达式与常规字符串匹配相似,可以不使用任何元字符,只进行字符匹配。也可以使用元字符或者限定符等其他符号进行模式的匹配

字符簇匹配

字符簇匹配模式是一种更加方便的模式方法,通常使用[]将一簇的字符包含在一起,常见的字符簇如下表

字符簇描述
[[:alpha:]]任何字母
[[:digit:]]任何数字
[[:alnum:]]任何字母和数字
[[:space:]]任何空白字符
[[:upper:]]任何大写字母
[[:lower:]]任何小写字母
[[:punct:]]任何标点符号
[[:xdigit:]]任何 16 进制的数字,相当于[0-9a-fA-F]

重复出现匹配

到目前为止,已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数

字符簇描述
^[a-zA-Z_]$所有的字母和下划线
^[[:alpha:]]{3}$所有的 3 个字母的单词
^a$字母 a
^a{4}$aaaa
^a{2,4}$aa,aaa 或 aaaa
^a{1,3}$a,aa 或 aaa
^a{2,}$包含多于两个 a 的字符串
^a{2,}如:aardvark 和 aaab,但 apple 不行
a{2,}如:baad 和 aaa,但 Nantucket 不行
\t{2}两个制表符
.{2}所有的两个字符

附录

菜鸟教程——正则表达式
正则表达式在线测试工具