轻松学会正则表达式!

        对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。无论你学习哪一门编程语言,几乎都不可避免的遇到正则表达式。本文就向你详细介绍一下正则表达式的用法,旨在梳理核心知识点,让你轻松学会正则表达式的用法!

一、基本概念

        正则表达式(regular expression) 描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等,替代了大篇幅的 if-else 代码来做一些数据校验

        通过使用正则表达式,可以:

  • 测试字符串内的模式
    例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
  • 替换文本
    可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
  • 基于模式匹配从字符串中提取子字符串
    可以查找文档内或输入域内特定的文本。

        正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。

二、元字符

1. 限定符

        限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {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?'。请注意在逗号和两个数之间不能有空格。

        

2. 定位符

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

正则表达式的定位符有:

字符 描述
^ 匹配输入字符串开始的位置。
$ 匹配输入字符串结尾的位置。
\b 匹配一个单词边界,即字与空格间的位置。
\B 非单词边界匹配。

         注意不能将限定符与定位符一起使用。由于在紧靠换行或者单词边界的前面或后面不能有一个以上位置,因此不允许诸如 ^* 之类的表达式。

3. 非打印字符

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

字符 描述
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

4. 特殊字符

        所谓特殊字符,就是一些有特殊含义的字符。若要匹配这些特殊字符,必须首先使字符"转义",即,将反斜杠字符\ 放在它们前面。下表列出了正则表达式中的特殊字符:

特别字符 描述
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 \{。
| 指明两项之间的一个选择。要匹配 |,请使用 \|。

 

三、基础语法 

1. 反义

  将原来的写法改成大写,意思与原来相反。

  •    "\W"   匹配任意不是字母,数字,下划线 的字符
  •    "\S"   匹配任意不是空白符的字符
  •  "\D"  匹配任意非数字的字符
  •    "\B"  匹配不是单词开头或结束的位置
  •    "[^abc]"  匹配除了abc以外的任意字符

2. 量词

        先解释关于量词所涉及到的三个重要的概念:

        贪婪(贪心):如"*"字符 贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的。

        懒惰(勉强):如 "?"  懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处

        占有:如"+" 占有量词会覆盖目标字符串,然后尝试寻找匹配内容 ,但它只尝试一次,不会回溯。

  •  "*"(贪婪)   重复零次或更多次

        例如"aaaaaaaa" 匹配字符串中所有的a  

        正则: "a*"   会出到所有的字符"a"

  • "+"(懒惰)   重复一次或更多次

   例如"aaaaaaaa" 匹配字符串中所有的a  

        正则: "a+"  会取到字符中所有的a字符,  

       注:"a+"与"a*"不同 

        "+":至少是1次

         "*":可以是0次

  • "?"(占有)   重复零次或一次

   例如"aaaaaaaa" 匹配字符串中的a

        正则 : "a?" 只会匹配一次,也就是结果只是单个字符a

懒惰限定词:

  "*?"   重复任意次,但尽可能少重复 

      如 "acbacb"  正则  "a.*?b" 只会取到第一个"acb" 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而"acbacb"最少字符的结果就是"acb" 

  "+?"  重复1次或更多次,但尽可能少重复

     与上面一样,只是至少要重复1次

  "??"  重复0次或1次,但尽可能少重复

      如 "aaacb" 正则 "a.??b" 只会取到最后的三个字符"acb"

  "{n,m}?"  重复n到m次,但尽可能少重复

          如 "aaaaaaaa"  正则 "a{0,m}" 因为最少是0次所以取到结果为空

  "{n,}?"    重复n次以上,但尽可能少重复

          如 "aaaaaaa"  正则 "a{1,}" 最少是1次所以取到结果为 "a"

3. 分组

        正则表达式中用小括号()来做分组,也就是括号中的内容作为一个整体。原本一个限定符是作用在与他左边最近的一个字符,使用分组之后,一个分组内字符的都限定。

        如:匹配字符串中包含0到多个ab开头:^(ab)*

4. 转义

        转义就是将元字符转义成普通的字符,做法是在要转义的字符前面加个斜杠,也就是 \ 即可。

5. 条件或

        正则用符号 | 来表示或,也叫做分支条件,当满足正则里的分支条件的任何一种条件时,都会当成是匹配成功。

6. 区间 

        正则提供一个元字符中括号 [ ] 来表示区间条件。

  • 限定0到9 可以写成[0-9]
  • 限定A-Z 写成[A-Z]
  • 限定某些数字 [165]

四 、高级语法

1. 零宽断言

  • 断言,就是说正则可以指明在指定的内容的前面或后面会出现满足指定规则的内容,
    比如"ss1aa2bb3",正则可以用断言找出aa2前面有bb3,也可以找出aa2后面有ss1.
  • 零宽:就是没有宽度,在正则中,断言只是匹配位置,不占字符。也就是说,匹配结果里是不会返回断言本身。

        几种类型的断言:

(1)正向先行断言(正前瞻):

  • 语法:(?=pattern)
  • 作用:匹配pattern表达式的前面内容,不返回本身。

(2)正向后行断言(正后顾):

  • 语法:(?<=pattern)
  • 作用:匹配pattern表达式的后面的内容,不返回本身。

(3)负向先行断言(负前瞻)

  • 语法:(?!pattern)
  • 作用:匹配非pattern表达式的前面内容,不返回本身。

(4)负向后行断言(负后顾)

  • 语法:(?<!pattern)
  • 作用:匹配非pattern表达式的后面内容,不返回本身。

2. 捕获和非捕获

        单纯说到捕获,他的意思是匹配表达式,但捕获通常和分组联系在一起,也就是“捕获组”。

        捕获组:匹配子表达式的内容,把匹配结果保存到内存中中数字编号或显示命名的组里,以深度优先进行编号,之后可以通过序号或名称来使用这些匹配结果。

        而根据命名方式的不同,又可以分为两种组:

(1)数字编号捕获组:

  • 语法:(exp)
  • 解释:从表达式左侧开始,每出现一个左括号和它对应的右括号之间的内容为一个分组,在分组中,第0组为整个表达式,第一组开始为分组。

(2)命名编号捕获组:

  • 语法:(?<name>exp)
  • 解释:分组的命名由表达式中的name指定

五、运算符优先级

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

        下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

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

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104434278