0
点赞
收藏
分享

微信扫一扫

正则表达式基础

才德的女子 2022-01-31 阅读 86

正则表达式基础

文章目录

定义

  • 正则表达式 (Regular Expression) : 描述了一种字符串匹配的模式,可以用来:检查一个串中是否含有符合某个规则的子串,并且可以得到这个子串;根据匹配规则对字符串进行灵活的替换操作。

用途

  • 正则表达式的主要应用对象是文本,可以在大多数的文本编辑器中使用。

    • 替换文本。可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
    • 基于模式匹配从字符串中提取子字符串。可以查找文档内或输入域内特定的文本。
  • 很多编程语言都支持使用正则表达式进行字符串操作。

    • 比如:pythonJavaJavaScriptRubyC# 等编程语言都支持大部分正则表达式的规则。
  • 测试字符串内的模式。

    • 比如可以测试输入字符串,查看字符串内是否出现电话号码模式或信用卡号码模式。这也被称作是数据验证1

正则表达式的用途十分广泛,不局限于上述的几个例子,还有很多应用场景可以使用正则表达式来达到事半功倍的效果!

语法规则

接下来就用以下模式来举例正则表达式的使用


匹配字符串 ⇒ ‘ 正 则 表 达 式 ‘ \stackrel{ `正则表达式`}{\Rightarrow} ​​​​​匹配结果

例如 : 匹配字符串 : abcd , 正则表达式为ab , 匹配结果为 : ab 则写成 abcd ⇒ a b \stackrel{ab}{\Rightarrow} ab​​ ab

为了方便,举例子统一用e.g. 2 该缩写代替


单个字符匹配

  • 字符 : 字母、数字、汉字、下划线、以及没有特殊定义的标点符号,都是字符。表达式中的字符,在匹配一个字符串的时候,匹配与之相同的一个字符。

    • e.g. a, 1, , _, ,, ' 等等
  • 字符串有两个及两个以上的字符组成的符号串

    • e.g. abcdef, 你好
  • 单个字符匹配的意思是 一个字符对应匹配一个字符

匹配简单字符

最简单的匹配规则 : 根据正则表达式中的字符进行挨个匹配, 顺序需要一致才能匹配成功

e.g.

  • abcdef ⇒ c d e \stackrel{cde}{\Rightarrow} cde​​​​​​ cde 匹配成功,匹配的位置从2开始,结束于5 (这里的下标统一从0开始, 顾头不顾腚即从下标2开始取值,下标5并不取值)
  • cdrf ⇒ a b c \stackrel{abc}{\Rightarrow} abc 匹配失败 匹配失败,没有找到对应的子串

转义字符

一些不方便书写的字符,需要使用转义符\来进行转义

  • \r : 代表回车
  • \n : 代表换行, 也叫换行符
  • \t : 代表缩进, 也叫制表符
  • \\ : 代表\本身
  • \^ : 代表^本身
  • \$ : 代表$本身
  • \. : 代表. 小数点本身
  • \* : 代表*
  • \? : 代表?

因为有些特殊字符在正则表达式中有特殊的含义, 要匹配那些特殊字符就必须使用转义才能匹配的到

e.g.

  • ab^cde$f*t ⇒ \ ∧ c d e \stackrel{ \backslash \wedge cde}{\Rightarrow} \cde ^cde 匹配成功,匹配的位置从2开始,结束于6 (这里的下标统一从0开始, 顾头不顾腚即从下标2开始取值,下标6并不取值)
  • cdfff*cc*? ⇒ \ ∗ c c \ ∗ \ ? \stackrel{ \backslash* cc\backslash*\backslash?}{\Rightarrow} \cc\\?​​ *cc*? 匹配成功,匹配的位置从5开始, 匹配到最后
  • 3.1415 ⇒ 3 \ . 14 \stackrel{ 3\backslash.14}{\Rightarrow} 3\.14 3.14 匹配成功,匹配的位置从0开始,结束于4
    在这里插入图片描述

匹配一类字符

指将字符按类别进行划分,比如数字类的字符,字母类的字符等等;而匹配一类字符是指匹配该类别字符中的任意一个字符

e.g. \d 可以匹配任意一个数字


  • \d : 代表任意一个数字; 0~9中的任意一个数字
  • \w : 代表任意一个字母或数字或下划线; 即A~Z, a~z, 0~9, _ 中的任意一个字符
  • \s : 代表空格、制表符、换页符和空白字符中的任意一个字符
  • . : 代表除了换行符(\n)3 以外的任意一个字符

e.g.

  • asd1314 ⇒ \ d \ d \stackrel{ \backslash d\backslash d}{\Rightarrow} \d\d13 匹配成功,正则表达式的含义是匹配两个数字;匹配的位置从3开始,结束于5

  • accc10086d ⇒ c . \ d \stackrel{ c.\backslash d}{\Rightarrow} c.\dcc1 匹配成功,正则表达式的含义是匹配一个字符c和任意一个除了换行的字符和一个数字;匹配的位置从2开始,结束于5

自定义匹配多种字符

  • 使用方括号 [ ] 包含的字符,能够匹配方括号内的任意一个字符。
  • [^ ] 包含的字符,则能够匹配除了方括号的字符之外的任意一个字符。
  • -可以指定范围, 比如 a-z是指字母a到字母z这段范围

注意 : 只是匹配其中任意一个,而不是多个; 换句话来说就是一个方括号匹配一个字符

e.g. [asdf@ss] 匹配括号内的任意一个字符,大白话就是括号内的字符可以当做一个集合, 只要匹配的字符属于该集合即可匹配成功!

  • jcabc ⇒ [ c j ] \stackrel{[cj]}{\Rightarrow} [cj]​​​ j 匹配成功,正则表达式的含义是匹配属于方括号内的字符;匹配的位置从0开始,结束于1

  • ckiab5@ ⇒ [ a b 2 @ ] \stackrel{[ab2@]}{\Rightarrow} [ab2@]​​ a 匹配成功,正则表达式的含义是匹配属于方括号内的字符;匹配的位置从3开始,结束于4

  • adcjcd ⇒ [ j d c ] [ k c l ] \stackrel{[jdc][kcl]}{\Rightarrow} [jdc][kcl]​​​​​ dc 匹配成功,正则表达式的含义是匹配属于方括号内的字符;匹配的位置从1开始,结束于2

  • abcd ⇒ [ ∧ a b c ] \stackrel{[\wedge abc]}{\Rightarrow} [abc]​​​​​ d **匹配成功,正则表达式的含义是匹配不属于方括号内的字符;匹配的位置从3开始,只匹配一个字符 **

  • abDcd ⇒ [ ∧ A − F 0 − 5 ] \stackrel{[\wedge A-F0-5]}{\Rightarrow} [AF05]​​​​ a 匹配成功,正则表达式的含义是匹配不属于方括号内的字符, 方括号内的含义是匹配除了AF之间的大写字母, 05的数字之外的字符 ;匹配的位置从0开始,只匹配一个字符

  • jdkdd ⇒ [ c − h ] \stackrel{[c-h]}{\Rightarrow} [ch]​​ d 匹配成功,正则表达式的含义是匹配属于方括号内的字符, 方括号内的含义是匹配ch之间的小写字母的字符 ;匹配的位置从1开始,只匹配一个字符


多个字符匹配

重复的次数放在被修饰的表达式的后面比如:[abcd][abcd]这是匹配两个字符的正则表达式,可以写成[abcd]{2},这样当有多个相同规则的表达式时能方便书写!

这种可以多个字符匹配的表达式还有如下几种:

  • {n} : 表达式重复n

    • e.g. 正则表达式 \w{3} 相当于 \w\w\w
    • a{6} 相当于 aaaaaa
    • \s{1}相当于 \s
  • {m,n} : 表达式至少重复m次, 最多重复n

    • e.g. 正则表达式 abc{1,2} 相当于匹配出 abcabcc
    • 注意 : {}的作用范围是前面的一个字符,而不是前面的所有字符
  • {m,} : 表达式至少重复m 次, 没有至多的次数

    • e.g. 正则表达式 a\d{2,} 的含义是匹配有至少有两个数字以上的子串; 可以匹配出的有a12, a111, a1233, a113344, …, a098765... 可以有无数个
    • abc1234dda ⇒ [ b c \ d ] { 2 , } \stackrel{[bc\backslash d]\{2,\}}{\Rightarrow} [bc\d]{2,}​​​​ bc1234 匹配成功,匹配位置从1开始,结束于7
  • ? : 匹配0次或1次,相当于{0,1}

    • e.g. 正则表达式ac? 可以匹配到的有a, ac
    • aabbcc ⇒ a [ c d ] ? \stackrel{a[cd]?}{\Rightarrow} a[cd]?​​ ab 匹配成功,匹配位置从1开始,结束于3
  • + : 表达式至少出现1次, 相当于{1,}

    • e.g. 正则表达式 a+c可以匹配出ac, aac, aaac,…
    • aabbcc ⇒ a + [ c d ] ? \stackrel{a+[cd]?}{\Rightarrow} a+[cd]?aab 匹配成功,匹配位置从0开始,结束于3
  • * : 表达式可以不出现或者出现任意次数, 相当于{0, }

    • e.g. 正则表达式abc*b 可以匹配出 abb, abcb, abccb, abccccb ,…
    • aabbccd ⇒ a [ c b ] ∗ d \stackrel{a[cb]*d}{\Rightarrow} a[cb]d​​​​ abbccd 匹配成功,匹配位置从1开始,匹配到结尾

抽象意义的特殊符号

这些特殊符号并不代表任何一个字符, 主要是做字符串的定位使用, 并不充当任何字符的"角色"

  • ^ : 与字符串开始的地方开始匹配, 不匹配任何字符

  • $ : 与字符串结束的地方匹配, 不匹配任何字符

  • \b : 匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符

e.g. 正则表达式 ^aaa 匹配要求从头开始为a

  • abcd ⇒ ∧ a b c \stackrel{\wedge abc}{\Rightarrow} abc​​ abc 匹配成功,正则表达式的含义是匹配a在开头的字符;匹配的位置从0开始,结束于3

  • cccabcdccc ⇒ ∧ a b c \stackrel{\wedge abc}{\Rightarrow} abc匹配失败, 因为a不在开头

  • a b c d ⇒ a b c $ 匹 配 失 败 abcd\stackrel{abc\$}{\Rightarrow}匹配失败 abcdabc$​​​匹配失败, 因为c不在结尾处

在这里插入图片描述

  • &&&avd ⇒ . \ b . \stackrel{.\backslash b.}{\Rightarrow} .\b.​​​ &a 匹配成功,正则表达式的含义是匹配不同类型的边界字符;匹配的位置从2开始,结束于4
  • @@@@1234 ⇒ . \ b . \stackrel{.\backslash b.}{\Rightarrow} .\b.@1 匹配成功,正则表达式的含义是正则表达式的含义是匹配不同类型的边界字符;匹配的位置从3开始,结束于5
  • yesterday, Friday, day, Sunday ⇒ \ b d a y \ b \stackrel{\backslash bday \backslash b}{\Rightarrow} \bday\b day 匹配成功,正则表达式的含义是匹配出只有day的字符串

表达式内部的子表达式

下面的符号会影响表达式内部的子表达式之间的关系

  • | : 左右两边表达式之间 “或” 关系,匹配左边或者右边
  • () : 这里可以分成两种含义
      1. 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰; 即可以操作字符串进行次数匹配。而没带括号()只能操作单个字符
      2. 取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到, 即可以把括号内的多个字符作为字符串进行匹配; 它与中括号[]不同之处在于中括号只匹配一个字符, 而()可以匹配多个字符

e.g. 表达式1 | 表达式2 正则表达式的含义是匹配表达式1匹配表达式2, 只要符合即可匹配

  • I am zeny, he is Mike ⇒ z e n y ∣ M i k e \stackrel{zeny|Mike}{\Rightarrow} zenyMike​​ zeny 匹配成功,位置从5开始到9

  • la la la la ha ha ha ha ⇒ ( h a \ s ∗ ) + \stackrel{(ha\backslash s*)+}{\Rightarrow} (ha\s)+ ha ha ha 匹配成功,表达式含义是匹配字符串ha加空格, 因为最后的ha没有带空格, 所以不匹配。从中可以看出*是操作整个括号内的字符, 而不仅仅是*号前面的单个字符

  • $12.2,¥10.1 ⇒ ¥ ( \ d + \ . ? \ d ∗ ) \stackrel{¥(\backslash d +\backslash .?\backslash d*)}{\Rightarrow} (\d+\.?\d)​​ ¥10.1 匹配成功, 单独获取括号范围内匹配的结果, 与方括号相比, ()可以匹配更多字符

高级规则

贪婪匹配

贪婪匹配是指在重复匹配的过程中不指定匹配次数时, 将会尽可能的匹配字符。

e.g. *, {m,n}, {m,}, +, ?这些没有确定的匹配次数的特殊符号, 他们将会尽可能多的匹配字符。其中?在匹配时匹配次数可以为0也可以为1, 但在匹配的过程中也是尽可能的要匹配, 这就是"贪婪"。

  • bbbaaabbbaa ⇒ ( a ) ( \ w + ) \stackrel{(a)(\backslash w +)}{\Rightarrow} (a)(\w+)​​ aaabbbaa 匹配成功, 正则表达式的含义是匹配a之后的所有字符, 默认是贪婪匹配的原则,就尽可能的匹配更多字符
  • baccccccccbb ⇒ ( a ) ( \ w + ) ( b ) \stackrel{(a)(\backslash w +)(b)}{\Rightarrow} (a)(\w+)(b) accccccccbb 匹配成功, 正则表达式的含义是匹配a之后的所有字符, 默认是贪婪匹配的原则,就尽可能的匹配更多字符,然后直到匹配最后的b

非贪婪匹配

一般的正则表达式表达式都是默认贪婪匹配。非贪婪匹配是指在重复匹配的过程中不指定匹配次数时, 将会尽可能的匹配字符。只需要在修饰匹配次数的特殊符号后加上?即可。

e.g. *, {m,n}, {m,}, +, ? 在这些没有确定的匹配次数的特殊符号后面加上?即可非贪婪匹配, 他们将会尽可能少的匹配字符。

  • bbbabbb ⇒ ( a ) ( \ w + ? ) \stackrel{(a)(\backslash w +?)}{\Rightarrow} (a)(\w+?)​​​ ab 匹配成功, 正则表达式的含义是匹配a之后的第一个字符, 非贪婪匹配的原则,就尽可能的匹配更少的字符
  • bbbabbba ⇒ ( a ) ( \ w + ? ) ( a ) \stackrel{(a)(\backslash w +?)(a)}{\Rightarrow} (a)(\w+?)(a)​​​​ abbba 匹配成功, 正则表达式的含义是匹配a之后的字符, 非贪婪匹配的原则,因为要匹配到后面的a, 就尽可能的匹配更少的字符直到字符a

再来举个贪婪匹配和非贪婪匹配区别的例子

  • <td><p>aa</p></td><td><p>bb</p></td> ⇒ ( < t d > ( . ∗ ) < / t d > ) ( a ) \stackrel{(<td>(.*)</td>)(a)}{\Rightarrow} (<td>(.)</td>)(a)<td><p>aa</p></td><td><p>bb</p></td>
  • <td><p>aa</p></td><td><p>bb</p></td> ⇒ ( < t d > ( . ∗ ? ) < / t d > ) ( a ) \stackrel{(<td>(.*?)</td>)(a)}{\Rightarrow} (<td>(.?)</td>)(a)​​ <td><p>aa</p></td>

它们最直接的区别是贪婪匹配要匹配到更多的</td> 而非贪婪匹配只匹配到第一个</td>即可

反向引用

  • 表达式后边的部分,可以引用前面 “括号内的子匹配已经匹配到的字符串”。这也叫反向引用
    • 引用方法是 “” 加上一个数字。\1 引用第 1 对括号内匹配到的字符串,\2 引用第 2 对括号内匹配到的字符串……以此类推
    • 如果一对括号内包含另一对括号,则外层的括号先排序号。大白话就是哪一对的左括号 “(” 在最前面,那这一对就先排序号。

e.g."Hello", 'hi' ⇒ ( " ∣ ′ ) ( . ∗ ? ) ( \ 1 ) ) ( a ) \stackrel{( " |')(.*?)(\backslash 1))(a)}{\Rightarrow} (")(.?)(\1))(a)​​​​​​ "Hello" 'hi' 匹配成功, 正则表达式的含义是匹配"或者'之间的内容; (\1)是指重复第一个括号的规则, 匹配到两段字符串。

e.g. aa bbbb abcdefg ccccc 111121111 ⇒ ( \ w ) ( \ 1 ) { 4 , } \stackrel{(\backslash w)(\backslash 1)\{4,\}}{\Rightarrow} (\w)(\1){4,} ccccc 匹配成功, 正则表达式的含义是匹配至少连续5次相同的字符; (\w)指匹配到的任意字符, (\1)是指重复第一个括号匹配到的内容,而{4,}则是匹配(\1)的内容至少4次以上; 因此就会匹配到至少5次相同的字符。

预搜索与反向搜索


正向预搜索 : 格式有(?=xxxxx), (?!xxxxx) ; 在被匹配的字符串中,它对所处的 “缝隙” 或者 “两头” 附加的条件
是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。

e.g. Windows 10 Windows XP ⇒ W i n d o w s ( ? = N T ∣ X P ) \stackrel{Windows (?=NT|XP)}{\Rightarrow} Windows(?=NTXP) Windows 匹配成功, 匹配到的Windows 后面的字符是否等于NTXP

请添加图片描述

e.g. Windows 10 Windows XP ⇒ W i n d o w s ( ? ! N T ∣ X P ) \stackrel{Windows (?!NT|XP)}{\Rightarrow} Windows(?!NTXP)Windows 匹配成功, 匹配到的Windows 后面的字符是否不等于NTXP

请添加图片描述


反向预搜索 : 格式有(?<=xxxxx), (?<!xxxxxx); 反向预搜索要求的条件是:所在缝隙的 “左侧”,
两种格式分别要求必须能够匹配和必须不能够匹配指定表达式,而不是去判断右侧。与 “正向预
搜索” 一样的是:它们都是对所在缝隙的一种附加条件,本身都不匹配任何字符。

e.g. 1234567890123456 ⇒ ( ? < = \ d { 4 } ) \ d + ( ? = \ d { 4 } ) \stackrel{(?<=\backslash d\{4\})\backslash d+(?= \backslash d\{4\})}{\Rightarrow} (?<=\d{4})\d+(?=\d{4})ccccc 匹配成功, 正则表达式的含义是将匹配除了前 4 个数字和后 4 个数字之外的中间 8 个数字


其他通用规则

  • 正则表达式中可以使用\xXX\uXXXX 表示一个字符 (X是以十六进制的形式表示)

    • \xXX : 编号在 0~ 255 范围的字符
    • 空格可以使用\x20
    • \uXXXX : 任何字符可以使用\u 再加上其编号的4位十六进制数表示
    • \u4E2D
  • \s, \d, \w, \b 已经表示了特殊的意义,但对应的大写字母表示相反的意义。

    • \S : 匹配所有非空白字符
    • \D : 匹配所有的非数字的字符
    • \W : 匹配所有的字母、数字、下划线以外的字符
    • \B : 匹配非单词边界,即左右两边都是\w范围或者两边都不是\w范围时的字符缝隙
  • 在表达式中有特殊意义,需要转义符转义才能得到本身的字符

    • \^
    • \$
    • \(\)
    • \[\]
    • \{\}
    • \.
    • \?
    • \+
    • \*
    • \|
  • 如果()内的子表达式如果希望不被记录可以使用(?:xxxxx)的格式

    • e.g. a bbccdd efg ⇒ ( ? : ( \ w ) \ 1 ) \stackrel{(?:(\backslash w)\backslash 1)}{\Rightarrow} (?:(\w)\1)​​​ bbccdd 匹配成功, 括号 (?:)
      范围的匹配结果不进行记录,因此(\w) 使用 \1 来引用

最后

几点建议

  1. 如果要求表达式所匹配的内容是整个字符串,而不是从字符串中找一部分,那么可以在表达式的首尾使用 ^$,比如:^\d+$ 要求整个字符串只有数字。
  2. 如果要求匹配的内容是一个完整的单词,而不会是单词的一部分,那么在表达式首尾使用\b,比如:使用\b(if|while|else|void|int……)\b 来匹配程序中的关键字。
  3. 合理选择贪婪模式与非贪婪模式。
  4. 表达式不要匹配空字符串。否则会一直得到匹配成功,而结果什么都没有匹配到。
  5. | 的左右两边,对某个字符最好只有一边可以匹配,这样,不会因为 | 两边的表达式因为交换位置而有所不同。
  6. 能匹配空字符串的子匹配不要循环无限次。
  7. 多些练习正则表达式的用法, 光看是记不住的和练不熟的。它可以很灵活地使用,但只要掌握基础就很容易能上手使用


举个使用正则表达式的例子:

  • 这是哔哩哔哩网站首页的部分源代码(具体的可以到哔哩哔哩网站首页,鼠标右键点击查看源代码即可复制到源代码)
  • 将源代码复制到VScode的集成开发环境中

比如:我们要提取出所有的视频链接

在这里插入图片描述

  • 观察视频链接的规律
    在这里插入图片描述

  • 点击开启VScode的查找功能, 并开启正则表达式的功能, 输入https://www.bilibili.com/video/.*?(?=")即可匹配到所有视频链接
    在这里插入图片描述

  • 选所有匹配项后, Ctrl+C复制出来即可

在这里插入图片描述
16条视频链接
在这里插入图片描述
ok, 上述只是个简单的正则表达式的操作, 还有很多玩法可自行探索!

-------- -----ENDING----- --------

  1. 这种数据验证常见的应用场景有调查问卷,网页的信息填写等等,验证你填入的信息是否符合某种格式; 比如输入邮箱号的输入框, 则会判断你输入的邮箱号是否符合邮箱的格式,一般邮箱号都带有@符号; 再比如手机号码(国内通用11为手机号), 则填入的手机号必须符合11位纯数字的格式。这些都可以用正则表达式来实现。 ↩︎

  2. 例如 (源自拉丁文exempli gratia); 这是举栗子的意思! ↩︎

  3. 大白话就是换行了就不匹配了 ↩︎

举报

相关推荐

0 条评论