正则表达式简介

来源:互联网 发布:安卓优化软件排行榜 编辑:程序博客网 时间:2024/04/30 18:26

什么是正则表达式

正则表达式也叫做匹配模式(Pattern),它由一组具有特定含义的字符串组成,通常用于匹配和替换文本。

正则表达式看上去并不像某种语言或者某个技术那么重要,仅靠正则你无法写出一个应用程序来。然后,它们总会出现在你的开发过程中,不管是进行表单验证,还是高亮显示搜索结果,又或是进行URL地址映射,总需要使用它们。几乎所有的语言都对它进行了不同程度的支持,由此足见正则表达式在文本匹配中的地位。

正则表达式的基本元素

  • 普通字符(literal character) >普通字符包括大小写的字母和数字,如 “a” “1”
  • 元字符(metacharacter) >元字符是一些具有特殊含义的字符,包括 \ ^ $ . | ? * + ( ) [ ] { }
  • 转义字符(escape character) >转移字符用于将元字符转换为普通字符,比如,当我们需要匹配字符”\”时,对应的正则表达式为”\ \”
    预备知识

  • 字符串组成

    对于字符串”abc”而言,包括三个字符和四个位置

  • 占有字符和零宽度

    正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的;如果子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配结果中,那么就认为这个子表达式是零宽度的。

占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。

  • #### 控制权和传动
    正则的匹配过程,通常情况下都是由一个子表达式(可能为一个普通字符、元字符或元字符序列组成)取得控制权,从字符串的某一位置开始尝试匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的。

如正则表达式:(子表达式一)(子表达式二)

假设(子表达式一)为零宽度表达式,由于它匹配开始和结束的位置是同一个,如位置0,那么(子表达式二)是从位置0开始尝试匹配的。

假设(子表达式一)为占有字符的表达式,由于它匹配开始和结束的位置不是同一个,如匹配成功开始于位置0,结束于位置2,那么(子表达式二)是从位置2开始尝试匹配的。

而对于整个表达式来说,通常是由字符串位置0开始尝试匹配的。如果在位置0开始的尝试,匹配到字符串某一位置时整个表达式匹配失败,那么引擎会使正则向前传动,整个表达式从位置1开始重新尝试匹配,依此类推,直到报告匹配成功或尝试到最后一个位置后报告匹配失败。

  • #### 匹配过程例子1:
    源字符串:abc

正则表达式:abc

匹配过程:

首先由字符“a”取得控制权,从位置0开始匹配,由“a”来匹配“a”,匹配成功,控制权交给字符“b”;由于“a”已被“a”匹配,所以“b”从位置1开始尝试匹配,由“b”来匹配“b”,匹配成功,控制权交给“c”;由“c”来匹配“c”,匹配成功。

此时正则表达式匹配完成,报告匹配成功。匹配结果为“abc”,开始位置为0,结束位置为3。

  • #### 匹配过程例子2:
    源字符串:abd

正则表达式:ab?c

匹配过程:

首先由字符“a”取得控制权,从位置0开始匹配,由“a”来匹配“a”,匹配成功,控制权交给字符“b?”;先尝试进行匹配,由“b?”来匹配“b”,同时记录一个备选状态,匹配成功,控制权交给“c”;由“c”来匹配“d”,匹配失败,此时进行回溯,找到记录的备选状态,“b?”忽略匹配,即“b?”不匹配“b”,让出控制权,把控制权交给“c”;由“c”来匹配“b”,匹配失败。此时第一轮匹配尝试失败。

正则引擎使正则向前传动,由位置1开始尝试匹配,由“a”来匹配“b”,匹配失败,没有备选状态,第二轮匹配尝试失败。

继续向前传动,直到在位置3尝试匹配失败,匹配结束。此时报告整个表达式匹配失败。

  • #### 匹配过程例子3:
    源字符串:a12

正则表达式:?=[a-z][a-z0-9]+$

元字符“”和“$”匹配的只是位置,顺序环视“(?=[a-z])”只进行匹配,并不占有字符,也不将匹配的内容保存到最终的匹配结果,所以都是零宽度的。

这个正则的意义就是匹配由字母和数字组成的,第一个字符是字母的字符串。

匹配过程:

首先由元字符“”取得控制权,从位置0开始匹配,“”匹配的就是开始位置“位置0”,匹配成功,控制权交给顺序环视“(?=[a-z])”;

“(?=[a-z])”要求它所在位置右侧必须是字母才能匹配成功,零宽度的子表达式之间是不互斥的,即同一个位置可以同时由多个零宽度子表达式匹配,所以它也是从位置0尝试进行匹配,位置0的右侧是字符“a”,符合要求,匹配成功,控制权交给“[a-z0-9]+”;

因为“(?=[a-z])”只进行匹配,并不将匹配到的内容保存到最后结果,并且“(?=[a-z])”匹配成功的位置是位置0,所以“[a-z0-9]+”也是从位置0开始尝试匹配的,“[a-z0-9]+”首先尝试匹配“a”,匹配成功,继续尝试匹配,可以成功匹配接下来的“1”和“2”,此时已经匹配到位置3,位置3的右侧已没有字符,这时会把控制权交给“$”;

元字符“$”从位置3开始尝试匹配,它匹配的是结束位置,也就是“位置3”,匹配成功。

此时正则表达式匹配完成,报告匹配成功。匹配结果为“a12”,开始位置为0,结束位置为3。其中“”匹配位置0,“(?=[a-z])”匹配位置0,“[a-z0-9]+”匹配字符串“a12”,“$”匹配位置3。

基本语法

1.匹配固定字符

Text: artificial intelligence

Regex: i

Text: Instead of crying, I shouted hello world on my birth.

Regex: hello

2.匹配任意单个字符(用元字符 .)

Text: regular.doc regular1.exe regular2.dat expression.doc express.dat

Regex: regular.

Regex: .e..

3.匹配元字符 . 本身

Text: regular.exe regular1.exe

Regex: r.

4.匹配字符组

有时候我们只希望匹配某几个字符中的一个,比如,我们要匹配”head”, “heat”这两个单词中的一个。正则提供了字符组来解决这个问题,它的语法是”[dt]”

Text:bread heay head heat

Regex: hea[td]

5.在字符组中使用字符区间

“[012…9]” —–> “[0-9]”

“[0123]” —–> “[0-3]”
“[abc…z]” —–> “[a-z]”
“[bcde]” —–> “[b-e]”
“[CDE]” —–> “[C-E]”

这个区间的起始字符和结束字符是依据ASCII值的大小,匹配ASCII码位于起始字符和结束字符之间的所有字符。

6.反义字符组

匹配除了字符集合意外的字符。语法是”[字符集合]”

如[1-3]

7.匹配特殊字符

  • ##### 匹配元字符
    元字符 匹配方式 \ \ \ ^ \ ^   … …
  • ##### 匹配空字符
    匹配方式 描述 \f 换页符 \n 换行符 \r 回车符 \t 制表符 \v 垂直制表符

8.预定义字符

匹配方式 描述 . 任何字符 \d 数字 \D 非数字 \s 空白字符 \S 非空白字符 \w 单词字符 \W 非单词字符

9.量词

贪婪 惰性 描述 X? X?? 匹配 X 零次或一次 X* X*? 匹配 X 零次或多次 X+ X+? 匹配 X 一次或多次 X{n} X{n}? 匹配 X n 次 X{n,} X{n,}? 匹配 X 至少 n 次 X{n,m} X{n,m}? 匹配 X 至少 n 次,但不多于 m 次
场景:找到html里面所有加粗的文本

Text: Jimmy is a junior developer in shanghai.

Regex: .*

Regex: .*?

场景: 将量词应用于子表达式

Text: catcatcatcat

Regex: cat{3}

Regex: (cat){3}

10 边界匹配

匹配单词的首末

Text: The cat scattered its food all over the room.

Regex: \bcat

Regex: cat\b

Regex: \bcat\b

边界的相对性

Text: The cat s-cat-tered its food all over the room.

Regex: \bcat\b

结论:

  • 当你对一个普通字符(如”s”)设置边界,它的边界是空格、分隔符、逗号、句号等
  • 当你对一个边界字符(如”-“)设置边界,它的边界是普通字符

匹配文本的首末

  • “”用于匹配文本首
  • “$”用于匹配文本末
    Text: city1 city2 city3

Regex: city\d?

Regex: city\d?$

11 后向引用

场景:去除重复出现的”of”和”up”

Text: The cost of of gas goes up up.

Regex: (of|up) (of|up)

Text: The cost of up.

Regex: (of|up) (of|up)

Text: The cost of up of of up up.

Regex: (of|up) \1

这里的\1相当于获取分组1对应的模式的内容,假如匹配时,模式是of,那\1就代表of。

分组
分组是通过从左往右计算开括号进行编号的。
比如:对于正则表达式((A)(B(C))),有以下4个分组
1. ((A)(B(C)))
2. (A)
3. (B(C))
4. (C)

后向引用一个常见的应用是匹配有效的html标签。

Text: bla bla bla

bla bla bla

Regex: .*?

12 环视(非获取匹配)

(?=Pattern) —-> 当前位置右边满足Pattern
(?!Pattern) —-> 当前位置右边不满足Pattern
(?

0 0
原创粉丝点击