目录html
正则表达式:使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。这个实际的正则表达式,也称为:模式(pattern)正则表达式
【查找】:一些软件中自带的搜索功能,是支持正则表达式的,能够实现有目的的高效率的快速搜索目标文件
如:Office软件,VS,通常的编程用的文本编辑器,Everything编程
【替换】:批量提取/替换有规律的字符串,如网络爬虫和模板引擎的标签库的开发数组
【检验】:各类开发语言中的使用,处理文本和大字符串,同时能够对用户输入的合法性验证(IP地址,特殊的订单号要求等)markdown
【匹配字符】:网络
元字符 | 说明 |
---|---|
. | 匹配除换行符之外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
【匹配位置(边界)】:app
元字符 | 说明 |
---|---|
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
【说明】less
一个元字符只匹配一个字符,如何匹配几个字符(即:字符串),要使用“重复匹配”符号。编辑器
位置元字符,只是表明位置,不匹配任何字符ide
语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x之外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母之外的任意字符 |
元字符是一些在正则表达式里有着特殊含义的字符。
由于元字符在正则表达式里有着特殊的含义,因此这些字符就没法用来表明它们自己。
故须要对一些特殊字符进行转义,使用 反斜杠“” 转义。
这一点和C#语言中语法,甚至markdown语法都同样,不赘述。
eg.
“\.” 匹配“.” “\* ” 匹配“*” “\?” 匹配“?” “\[” 匹配“[" “\\” 匹配“\"
(?# 注释内容)
语法 | 说明 |
---|---|
* | 重复零次或更屡次 |
+ | 重复一次或更屡次 |
? | 重复零次或一次 =={0,1} |
{n} | 重复n次 |
{n,} | 重复n次或更屡次 |
{n,m} | 重复n到m次 (不是n或m次) |
【定义】 使用方括号“[ ]”表示一个集合,使用连字符“-”表示从某某到某某
【注意】"-"(连字符)是一个特殊的元字符,做为元字符它只能用在[和]之间。在字符集合之外的地方,一只是一个普通字符,只能与一自己相匹配。所以,在正则表达式里,一字符不须要被转义。
【例子】
[A-Z]匹配从A到z的全部大写字母。 [a-z]匹配从a到z的全部小写字母。 [A-F]匹配从A到F的全部大写字母。 [abcd]匹配a或b或c或d [0-9] == \d [a-z0-9A-Z_] == \w
【字符集取非】
字符集合一般用来指定一组必须匹配其中之一的字符。但在某些场合,咱们须要反过来作,给出一组不须要获得的字符。换句话说:除了那个字符集合里的字符,其余字符均可以匹配。
使用用元字符“^”来对字符集合求非。
【例子】
[0-9]匹配的是任何不是数字的字符
【定义】贪婪,即过分匹配。
*和+都是所谓的“贪婪型”元子符,它们在进行匹配时的行为模式是多多益善而不是适可而止的。
它们会尽量地从一段文本的开头一直匹配到这段文本的末尾,而不是从这段文本的开头匹配到碰到第一个匹配时为止。
正则表达式的做用就时快速准确的找到你想要的字符串,因此咱们更喜欢“懒惰”。
在不须要这种“贪婪行为”的时候该怎么办?
答案是使用这些元字符的“懒惰型”版本(“懒惰”在这里的含义是匹配尽量少的字符,与“贪婪型”元字符的行为模式恰好相反)。
【语法】懒惰型元字符的写法很简单,只要给贪婪型元字符加上一个?后缀便可。
经常使用的贪婪型元字符的懒惰型版本
语法 | 说明 |
---|---|
*? | 重复任意次,但尽量少重复 |
+? | 重复1次或更屡次,但尽量少重复 |
?? | 重复0次或1次,但尽量少重复 |
{n,m}? | 重复n到m次,但尽量少重复 |
{n,}? | 重复n次以上,但尽量少重复 |
【例1】:
字符串: This offer is not available to customers living in <B>AK</B>and <B>HI</B>. 贪婪型正则表达式:<B>.*</B> 结果(匹配到一个符合的字符串):<B>AK</B>and <B>HI</B> 懒惰型正则表达式:<B>.*?</B> 结果(匹配到两个符合的字符串): <B>AK</B> <B>AK</B>
【例2】:
字符串:aaabbb 贪婪正则表达式:a.*b 结果:aaabbb 懒惰正则表达式:a.*?b 结果:aaab
【语法】用“|”把不一样的规则分隔开
从左到右地测试每一个条件,若是知足了某个分枝的话,就不会去再管它以后的的条件了。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。
美国邮编的规则是5位数字,或者用连字号间隔的9位数字。
之因此要给出这个例子是由于它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。
若是你把它改为 \d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。
缘由是匹配分枝条件时,将会从左到右地测试每一个条件,若是知足了某个分枝的话,就不会去再管其它的条件了。
【语法】使用小括号“()”表示分组,分组的内容即子表达式
为何要分组?
举个例子
你想要在在字符串中匹配“abab"四个连续的字母,你想到使用正则表达式"ab"重复两次,即“ab{2}”
可是其实它却得不到你想要的结果,它匹配的是“abb”,正确的写法是使用分组“(ab){2}”。
【例子】
匹配IP地址:IP地址由四组数字构成,每组数字由1到3个数字字符构成,它们之间以英文句号分隔。
正则表达式:(\d{1,3}.){3}\d{1,3}
且不管是否正确,可是确实是使用了分组把“\d{1.3}.”重复了三次
可是:这个模式有什么不对的地方吗?从语法上讲,它彻底正确。说这个模式正确,是由于全部合法的IP地址都与之相匹配。但深刻研究一下就会发现,这个模式还能够匹配其余一些东西;说得明白点儿,不合法的IP地址也能与之相匹配。
IP地址由4个字节构成,IP地址中的4组数字分别对应着那4个字节,因此IP地址里的每组数字的取值范围也就是单个字节的表示范围,即0-255。这意味着IP地址里的每一组数字都不能大于255,但是上面那个模式还能匹配诸如34五、700、999之类的数字序列,而这些数字在P地址里都是非法的。
注意:有句话但愿你能紧紧记住:把必须匹配的状况考虑周全并写出一个匹配结果符合预期的正则表达式很容易,但把不须要匹配的状况也考虑周全并确保它们都将被排除在匹配结果之外每每要困可贵多。
那么通常怎么使用正则表达式匹配IP地址呢?
咱们来分析一下:
下面是一个合法的IP地址里的各组数字必须且只能符合的规则:
根据这些规则来构造一个相应的模式:
(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})l(1\d{2})|(2[0-4]\d)|(25[0-5]))
【注意】
1.一个“(子表达式)”就是一个分组,正则表达式的测试,默认是给他分配一个组号,并能够显示该组所匹配的内容。
关于组号的分配:
分组0对应整个正则表达式
实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--所以全部命名组的组号都大于未命名的组号
你可使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.(这句话生命意思呢?就时某个分组(exp),你把它写成(?:exp),则不会单独显示这一组匹配的值(可是总体的正则表达式正常匹配)
2.若以咱们不须要显示这组匹配的内容,则咱们可使用"(?:子表达式)"的形式。
eg.匹配百度云链接:
(?:https?:\/\/)?(?:yun|pan|eyun)\.baidu\.com\/(?:s\/\w*(((-)?\w*)*)?|share\/\S*\d\w*)
3.咱们能够给该分组起一个名字,使用 "(? <组名> 子表达式)"
【定义】后向引用(backreference)又称回溯引用:经过组号或是组名对以前定义的分组所匹配到的字符串的引用
【注意】:引用的是分组匹配到的字符串,而不是分组的正则表达式。因此:你能够把后向引用看做一个变量
后向引用方式:\组号或 \k <组名>
【例1】
查找文本中的重复单词
假设你有一段文本,你想把这段文本里全部连续重复出现的单词(打字错误,其中有一个单词输了两遍)找出来。
显然,在搜索某个单词的第二次出现时,这个单词必须是已知的。
回溯引用容许正则表达式模式引用前面的匹配结果(具体到这个例子,就是前面匹配到的单词)。
This is a block of of text. 正则表达式:\s+(\w+)\s+\1 结果: of of
【例2】
寻找一段标签语言中全部合法的各级标题
这个问题并无你想的那么简单,你要考虑的是每一级标题的标签的相互匹配。
文本: <BODY> <H1>Welcome to my Homepage</H1> Content is divided into two sections:<BR> <H2>C01dFusion</H2> Information about Macromedia ColdFusion. <H2>Wireless</H2> Information about Bluetooth,802.11, and more. <H2>This is not valid HTML</H3> </BODY> 正则表达式:<[Hh]([1-6])>.*</[Hh]\1> 结果: <H1>Welcome to my Homepage</H1> <H2>C01dFusion</H2> <H2>Wireless</H2> 注意:<H2>This is not valid HTML</H3>这个就不匹配
后向引用在替换中的使用:
注意在替换中,引用分组的方式是:$组号
【例子】
313-555-1234 248-555-9999 810-555-9000 正则表达式:(\d{3})(-)(\d{3})(-)(\d{4}) 替换为:($1) $3-$5 结果: (313) 555-1234 (248) 555-9999 (810) 555-9000
【定义】先后查找:使用正则表达式对某一个位置匹配,以后对位置的前、后内容进行查找.
【注意】匹配到的定位字符串是不返回的(专业术语:不消费)
向前查找(lookahead):在匹配的位置以前(左侧)查找
【语法】:(?=exp)
【例子】
字符串:I'm singing while you're dancing. 正则表达式:\b\w+(?=ing\b) 结果:sing和danc
向后查找(lookbehind):在匹配的位置以后(右侧)查找
【语法】:(?<=exp>)
【例子】
字符串:reading a book 正则表达式:(?<=\bre)\w+\b 结果:ading
把向前查找和向后查找结合起来
【例1】
正则表达式:(?<=\s)\d+(?=\s)
匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
【例2】
文本: <HEAD> <TITLE>Ben Forta's Homepage</TITLE> </HEAD> 正则表达式:(?<=TITLE>).+(?=</TITLE) 结果:Ben Forta's Homepage
分析:
向后查找:(?<=TITLE>),咱们匹配到“TITLE>”作为开始定位
向前查找:(?=</TITLE), 咱们匹配到“</TITLE”做为结束定位
(?<=TITLE>).+(?=</TITLE):这句正则表达式:即寻找一个不肯定长度的非换行符的字符串,这个字符串的开始位置是:TITLE>,结束位置是:</TITLE
【说明】
关于 “零宽断言” 是什么?
所谓的零宽断言其实就是先后查找。
其实:咱们使用先后查找首先要匹配一个字符串做为定位,这个字符串即便正则表达式最终匹配,最终匹配结果咱们也是不返回这个用来定位的字符串。即:所谓的返回的是0字节,也就是“零宽度(zero-width)”。
断言则就是字面理解那样--下一个结论。
正则表达式中只有当断言为真时才会继续进行匹配。
那么这么高大上 的名字怎么能不使用呢!
向前查找,也称:零宽度正预测先行断言
向后查找,也称:零宽度正回顾后发断言
【引入】
字符集合咱们使用“^”取非,表示不去匹配这些字符,一样向前向后查找同样有取非。
到目前为止正如你看到的那样,向前查找和向后查找一般用来匹配文本,其目的是为了肯定将被返回为匹配结果的文本的位置(经过指定匹配结果的先后必须是哪些文本)。
这种用法被称为正向前查找(positive lookahead)和正向后查找(positive lookbehind)。
术语“正”指的是寻找匹配的事实。
而对向前向后查找取非,则称为负先后查找(negative lookaround)
负先后查找的语法就是把正先后查找的等号换为感叹号
【定义1】负向前查找(negative lookahead)将向前查找不与给定模式相匹配的文本
【语法】:(?!exp)
【定义2】负向后查找(negative lookbehind)将向后查找不与给定模式相匹配的文本
【语法】:(?<!exp)
【例子】
文本:I paid $30 for 100 apples,50 oranges, and 60 pears.I saved $5 on this order. 只查找文本中的金额数字 分析:使用正向前查找 正则表达式:\b(?<=\$)\d+\b 结果:30和5 只查找文本中的非金额数字 分析:使用符向后查找 正则表达式:\b(?<!\$>)\d+\b 结果:100和50和60 注意:如果:(?<!\$>)\d+,会取到$30中的那个0
【分析】
\b(?<!$>)\d+\b :寻找一串数字(这串数字在文本中单独做为一个单词),可是这串数字的开头不能是"$"
【注意】深刻理解"零宽":
举一个例子:在文本中寻找一个单词,这个单词中须要含有q(能够在单词中的任何位置),可是q后面必定不能l连着字母u
如果不使用先后查找,你可能会这样写:\b\wq[^u]\w\b
注意这样写是不许确的,如果某一个单词以字母q结尾,也是知足咱们要寻找的单词的要求:含有q。
可是咱们写的那个正则表达式是匹配不到的,
为何呢?就是由于"[^u]"是占一个位置的,而零宽即意味着不占位置。
因此咱们这样写:\b\wq(?!u)\w\b
【例子】
文本:hello benq ,I'm qik 哈哈 正则表达式:\b\w*q[^u]\w*\b 结果:qik 正则表达式:\b\w*q(?!u)\w*\b 结果:benq和qik
平衡组/递归匹配
未完待续......
.NET Framework经过它的基本类库提供了强大和灵活的正则表达式支持,这些支持在全部的.NET语言和工具(包括ASP.NET、C#和Visual Studio.NET在内)里均可以使用。
NET里的正则表达式支持是经过Regex类(以及其余一些辅助类)提供的。
Regex类有如下一些方法:
IsMatch():测试在某个给定的字符串里是否能够找到一个匹配。 Match():搜索一个单个的匹配,该匹配将被为一个Match对象。 Matches():搜索全部的匹配,它们将被返回为一个MatchCo1lection对象。 Replace():在一个给定的字符串上进行替换操做。 Split():把一个字符串拆分为一个字符串数组。
利用各类静态函数,在无须建立和使用一个Regex类的状况下也能够执行一个正则表达式。
Regex.IsMatch():在功能上等价于IsMatch()方法。 Regex.Match():在功能上等价于Match()方法。 Regex.Matches():在功能上等价于Matches()方法。 Regex.Replace():在功能上等价于Replace()方法。 Regex.Split():在功能上等价于Split()方法。
注意事项:
要想使用正则表达式,必须用Imports System.Text.Regular-Expressions语句导入正则表达式对象。
若是只是临时须要使用正则表达式,上述静态函数是理想的选择。
正则表达式的选项须要使用Regex.Options属性给出,它是一个Regexoption枚举集合,你能够对这个枚举集合的各有关成员如Ignorecase、Multiline、singleline等进行设置。
.NET支持命名捕获,即容许对子表达式进行命名(这样就可使用名字而不是编号来引用它们了)。
参见:2.9 子表达式(分组)
命名一个子表达式的语法是?
引用这个回溯引用的语法是\k
在一个替换模式里引用它的语法是${name}。
在使用回溯引用的时候,$ `(反引号)将返回被匹配字符串前面的全部东西,$'(单引号)将返回被匹配字符串后面的全部东西,$+将返回最后一个被匹配的子表达式,$_将返回整个原始字符串,$&将返回整个被匹配字符串。
.NET Framework不支持使用\E、\一、L、\u和\U进行大小写转换。
.NET Framework不支持POSIX字符类。