【Regex】正则表达式总结

【Regex】正则表达式总结

前言

正则表达式在匹配字符串文本时非常出色,并且在很多语言中都支持正则表达式。

我归纳整理了下学习正则表达式时的知识点,所以就写了这篇博客。

一、正则表达式

1.概念

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

正则表达式(Regular expression),我们常用regex缩写来表示正则表达式。

简单来说,正则表达式就是一串有规则的字符串。这个有规则的字符串用来匹配另一个字符串。

2.作用

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:

  1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
  2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

用一个有规则的字符串(正则表达式)去匹配另一个字符串,可以判断是否匹配,也可以从另一个字符串中获取我们想要的特定部分(比如:你要判断用户输入的用户名是否规范,可以使用正则表达式来进行匹配)。

3.特点

正则表达式的特点是:

  1. 灵活性、逻辑性和功能性非常强;
  2. 可以迅速地用极简单的方式达到字符串的复杂控制。
  3. 对于刚接触的人来说,比较晦涩难懂。

正则表达式非常灵活,并且可以用很简单地用一串正则表达式去匹配一个字符串(比如:用代码控制会写很多代码,但是正则表示可能就一行)。

虽然刚开始接触会感觉比较难,万事开头难嘛,但是多学一些之后会感觉非常简单了!

4.初识正则表达式

4.1 准备
  • 软件
    我用来学习正则表达式软件是 RegexBuddy推荐使用 百度下载一下会简单使用即可)。
    简单使用:
4.2 基础练习

正则表达式可以分开学的,可以先使用软件或网站练习。

等熟悉了常用的正则表达式后,再到常用的语言中使用正则表达式。

  • 问题:给定一个字符串"hello regex 123,456",找出字符串中的所有数(尽可能大)。

  • 解决:使用正则的元字符(特殊意义的字符)和限定符(重复的次数)即可。(元字符和限定符我下面会讲到)

  • 正则表达式:==\d+== 或 ==[0-9]+==

二、正则表达式基础

1.元字符(特殊字符)

正则表达式语言由两种基本字符类型组成:原义(正常)文本字符和元字符。元字符使正则表达式具有处理能力。所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。

正则表达式主要依赖于元字符。 元字符不代表他们本身的字面意思,他们都有特殊的含义。一些元字符写在方括号中的时候有一些特殊的意思。

元字符就是一些特殊意义的专用字符。元字符解释:一组代替一个或多个字符的字符。

1.1 简写字符集(可打印字符)

可打印字符就是在显示器上输出能够看得见的。

如:在ASCII表中,打印字符是指除ASCII码0~31及127(共33个)是控制字符或通信专用字符,剩余的都属于可打印字符。

字符描述
.匹配除换行符 \n 之外的任何单字符。
\d匹配数字: [0-9]
\D匹配非数字: [^\d]
\w匹配所有字母数字,等同于 [a-zA-Z0-9_]
\W匹配所有非字母数字,即符号,等同于: [^\w]
[ ]字符集合。匹配所包含的任意一个字符(常用0-9表示0到9,a-z表示小写字母a到z,大写字母同理)。例如 [abcde] 可以匹配到 "hello" 中的 'e'。
1.2 简写字符集(非打印字符)

什么是非打印字符呢?非打印字符指在计算机中有一些字符是确确实实存在,但是它们不能够显示或者打印出来。

如:在ASCII表中,非打印字符是指ASCII码0~31及127(共33个)是控制字符或通信专用字符,属于非可打印字符。

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

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

限定符就是用来指定某一个正则表达式需要重复多少次才匹配。

字符描述
?匹配前面的子表达式零次或一次。如:cs? 表示匹配前面s可以出现零次或一次(s可以重复0或1次),可以匹配到 c、cs但是不能匹配到css
*匹配前面的子表达式零次或多次。    如:cs* 表示匹配前面s可以出现零次或多次(s可以重复0次以上),可以匹配到 c、cs、css
+匹配前面的子表达式一次或多次。如:cs+ 表示匹配前面s可以出现一次或多次(s可以重复1次以上),可以匹配到 cs、css,但是不能匹配到c
n 是一个非负整数。匹配确定的 n 次。如:cs{2} 表示匹配前面s出现2次(s可以重复2次以上),可以匹配到 css,但是不能匹配到c、cs、csss
{n,}n 是一个非负整数。至少匹配n 次。如:cs{2,} 表示匹配前面s至少2次及以上(s可以重复2以上),可以匹配到 css、csss、但是不能匹配到cs
{n,m}n 和 m 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。如:cs{2,4} 表示匹配前面s至少2次最多4次(s可以重复2-4次),可以匹配到 css、csss但是不能匹配到cs
1.4 定位符

定位符使您能够将正则表达式固定到行首或行尾。它们还使您能够创建这样的正则表达式,这些正则表达式出现在一个单词内、在一个单词的开头或者一个单词的结尾。
定位符用来描述字符串或单词的边界,^ 和 $ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。

字符描述
^匹配输入字符串的开始位置。^的另一种用法:在方括号表达式中使用(如[^ ]),当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。
$匹配输入字符串的结尾位置。
\b匹配一个单词边界,即字与空格间的位置。
\B非单词边界匹配。
1.5 特殊字符

特殊字符就是指有特殊意义的字符。如果需要用到特殊字符的原本字符,需要使用转义字符 \ 进行转义(如:你想匹配 字符,则需要这样写 \)。

字符描述
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
.匹配除换行符 \n 之外的任何单字符。
? , * , +, { }请查看上面1.3 限定符。
^ 和 $请查看上面1.4 定位符。
( )捕获组,用来把正则表达式中子表达式匹配的内容,保存到内存中,用数字标号或显示命名的组里,方便后面引用。
[表示字符集合的开始。经常与 ] 搭配使用,[] 表示字符集合,匹配所包含的任意一个字符。例如 [abcde] 可以匹配到 "hello" 中的 'e'。
|或运算符。例如,正则 c|s 将匹配 c 或者 s

三、正则表达式进阶

1.零宽断言

用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。

这名词可能有点难理解,我用我的理解来解释一下:

  • 零宽:就是0宽度,没有宽度(就是正则匹配时不包含这些内容)。

  • 断言:断定某个位置满足一定条件的言论(就是断定某个位置,这个位置应该是满足一定条件的)。

  • 零宽断言简单理解:就是像定位符 \b,^,$ 一样用来指定某个位置,断定某个位置一定有满足某个条件的表达式。

字符描述
(?=pattern)                              正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?!pattern)正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<!pattern)反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。
1.1 正向肯定预查

正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

  • 语法:(?=pattern)
  • 正则: ==Windows(?=95|98|NT|2000)==
  • 正则解释:匹配Windows,后面为95或98或NT或2000的字符串(匹配结果仅包含Windows)。
1.2 反向肯定预查

反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。

  • 语法:(?<=pattern)
  • 正则: ==(?<=95|98|NT|2000)Windows==
  • 正则解释:匹配Windows,前面为95或98或NT或2000的字符串(匹配结果仅包含Windows)。
1.3 正向否定预查

正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

  • 语法:(?!pattern)
  • 正则: ==Windows(?!95|98|NT|2000)==
  • 正则解释:匹配Windows,后面为95或98或NT或2000的字符串(匹配结果仅包含Windows)。
1.4 反向否定预查

反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。

  • 语法:(?<!pattern)
  • 正则: ==(?<!95|98|NT|2000)Windows==
  • 正则解释:匹配Windows,前面 为95或98或NT或2000的字符串(匹配结果仅包含Windows)。

四、正则表达式补充

1.捕获

字符描述
( )                    捕获组,用来把正则表达式中子表达式匹配的内容,保存到内存中,用数字标号或显示命名的组里,方便后面引用。
\num匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
(?:pattern)匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
1.1 捕获组

捕获组,用来把正则表达式中子表达式匹配的内容,保存到内存中,用数字标号或显示命名的组里,方便后面引用。

捕获组 () 我们在 二、正则表达式基础的 中的 1.5 特殊字符 看到过。

正则表达式会左侧开始,每出现一个左括号"("记做一个分组,分组编号从 1 开始。0 代表整个表达式。

  • 语法:(pattern)
  • 正则: ==([1-9])(\d)==
  • 正则解释:匹配一个两位数。([1-9])为捕获组1,表示1-9开头的数。(\d)为捕获组2,表示任意一个数(匹配结果包含12)。
1.2 反向引用

匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。

上面讲的捕获组,会给每一对括号记作一个分组,分组编号从 1 开始。0 代表整个表达式。现在我们学捕获组的引用(反向引用)。

  • 语法:\num
  • 正则: ==([1-9])(\d)\2==
  • 正则解释:匹配一个三位数。([1-9])为捕获组1,表示1-9开头的数。(\d)为捕获组2,表示任意一个数。\2表示反向引用捕获组2( 即(\d) )(匹配结果包含122)。
1.3 非捕获组

匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

  • 语法:(?:pattern)
  • 正则: ==industr(?:y|ies)==
  • 正则解释:匹配industr,结尾为y或ies的字符串(匹配结果包含y和ies)。

2.贪婪匹配与非贪婪匹配 + 否定字符集

'?' 和 '^' 这两个元字符我们在 二、正则表达式基础的 中的 1.3 限定符1.4 定位符 看到过。

字符描述
?    当该字符紧跟在任何一个其他限制符 (*, +, ?, , {n,}, {n,m} ) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "cs12345",正则表达式'\d{3,}?' 将匹配 "123",而 '\d{3,}' 将匹配 '12345'。
^匹配输入字符串的开始位置。^的另一种用法:在方括号表达式中使用(如[^ ]),当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。
2.1 贪婪匹配与非贪婪

当该字符紧跟在任何一个其他限制符 (*, +, ?, , {n,}, {n,m} ) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "cs12345",正则表达式'\d{3,}?' 将匹配 "123",而 '\d{3,}' 将匹配 '12345'。

  • 贪婪:匹配字符串时,尽可能匹配多的字符串。例如,对于字符串"cs12345"用正则 ==\d{3,}== 匹配时,可以匹配到12345。
    • 语法:默认使用 (*, +, ?, , {n,}, {n,m} ) 时,匹配模式就是贪婪的(尽可能多的匹配字符串)。
    • 正则:==\d{3,}==
    • 正则解释:匹配0-9的数字(\d)最少重复3次以上({3,})(匹配结果为12345)。

  • 非贪婪:匹配字符串时,尽可能匹配少的字符串。例如,对于字符串"cs12345"用正则 ==\d{3,}?== 匹配时,可以匹配到123,但匹配不到12345。
    • 语法 使用 (*, +, ?, , {n,}, {n,m} ) 时,在这六个限定符后加上?
    • 正则:==\d{3,}==
    • 正则解释:匹配0-9的数字(\d)最少重复3次以上({3,})且是非贪婪的(?)(匹配结果为123)。
2.2 否定字符集

匹配输入字符串的开始位置。^的另一种用法:在方括号表达式中使用(如[^ ]),当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。

和字符集 [ ] 搭配使用,表示不包含在某个字符集的字符。例如,"[^a-z]" 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。

  • 语法:[^]
  • 正则: ==[^a-z]==
  • 正则解释:匹配任何非a-z字母的单个字符。

参考

正则表达式百度百科:https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fr=aladdin

菜鸟正则表达式教程:https://www.runoob.com/regexp/regexp-tutorial.html(推荐)

learn-regex:https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md