正则表达式

来源:互联网 发布:sql select count 1 编辑:程序博客网 时间:2024/06/12 01:23

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码,最多的用途就是匹配带有一定规律的字符串

常用元字符(metachracter)

  • . - 匹配除换行(\r\n)以外的任意字符
  • \w - 匹配包括下划线的任何单词字符(unicode),类似但不等价于[A-Za-z0-9_]
  • \s - 匹配任意的不可见字符,等价于[\f\n\r\t\v]
  • \d - 匹配数字
  • \b - 匹配单词的开始或结束
  • ^ - 匹配字符串的开始
  • $ - 匹配字符串的结束

\b^$

看起来\b^$相同,但是是有差异的

  • \b是表示一个单词的边界,一个单词例如一连串的英文和数字、或者一句中文
  • ^$是表示一个字符串的开始和结尾,分割字符串的仅是那些不可见字符
/b44/b | 匹配字符串 | !@#$%44&*() | -> 匹配成功,因为"44"这个字符串的左右都不是英文数字,所以这里"44"就是一个单词^44$ | 匹配字符串 | !@#$%44&*() | -> 匹配失败,因为这个字符串的开头不是'4'而是'!',结尾不是'4'而是')'/b44/b | 匹配字符串 | 4432 | 和 | 4432出 | -> 前者成功,后者失败,前者是因为'出''4'并不是同种类型的字符,所以这里有三个单词"44""出""32";而后者"4432"是一个单词,并不满足"44"之后是单词结尾^44 | 匹配字符串 | 4432 | 和 | 出4432 | -> 前者成功,后者失败,这里只用考虑整个字符串是不是以"44"开头的

另外有些正则表达式处理提供 多行(Multiline) 选项,使得^$也匹配\n\r的前后位置
JavaScript RegExp \b 元字符
正则匹配中 ^ $ 和 \b 的区别
JavaScript multiline 属性

字符转义

和很多语言一样,也是用\符号来转义,因此在JavaScript当中有时候可能要两次转义

重复限定符

元字符只是匹配一个位置或者字符,当我们想匹配多个或者不确定个数元字符时,就要搭配上下面这些限定符使用了

  • * - 重复次数 >= 0
  • + - 重复次数 >= 1
  • ? - 重复次数 == 0 或 重复次数 == 1
  • {n} - 重复次数 == n
  • {n,} - 重复次数 >= n
  • {n,m} - m >= 重复次数 >= n
0\d{2}-\d{8} - 匹配上010-12345678\ba\w*\b - 匹配一个单词以'a'开头,之后任意个数字字母,直到单词的结尾Windows\d+ - 匹配'Windows'后面跟上不少于一个数字

字符类

如果没有特定的元字符,比如只匹配’c’、’m’、’d’,此时用[]框住,就像一个集合一样

[cmd] - 只匹配'c''m''d'这三个字符[.!?] - 只匹配'.''!''?'这三个标点符号(这里的'.'必然不是元字符)

也可以在框中指定一个范围

[0-9] - 匹配数字  \(?0\d{2}[) -]?\d{8}    首先"\(?"说明一开始可以出现0次或1'('    然后是必须要出现一个'0'    接着是两个数字    之后是出现0次或1'('' ''-'    最后是8个数字可以匹配:020-12345678、(020)1234567802012345678

分枝条件

不难看出之前那个表达式\(?0\d{2}[) -]?\d{8}同样可以匹配例如(020-12345678010)12345678这种不正确的格式,正则表达式中用|来表示分枝,只要满足一个分支都算匹配成功,且当从左至右第一个分支匹配成功后,后面的分支都不会参与测试

\(0\d{2,3}\)[- ]?\d{8}|0\d{2,3}[- ]?\d{8} - 解决上面错误格式问题,以及将区号扩展为3或4位

分组

使用()来指定子表达式的方式叫做分组,这样我们就可以加上限定符重复多个字符

(\d{1,3}\.){3}\d{1,3} - 一个用来简单匹配IP地址的表达式,这里重复\d{1,3}\.这个组3次,最后加上\d{1,3},但是我们知道IP地址每位最大是255,因此需要分枝  ((2[0-4]\d|25[0-5]|[01]?\d?\d)\.){3}(2[0-4]\d|25[0-5]|[01]?\d?\d) - 这样就可以解决最大数字问题了

反义

查找不属于某个元字符(或者字符类、分组)的字符,有以下反义

  • \W - 匹配不包括下划线的任何非单词字符(unicode)
  • \S - 匹配任意不是空白字符的字符
  • \D - 匹配任意不是数字的字符
  • \B - 匹配不是单词开头或结束的位置
  • [^xyz] - 匹配除’x’或’y’或’z’以外的任意字符
\S+ - 匹配不包含空白字符的字符串  <a[^>]+> - 匹配用'<>'框住且以'a'开头的字符串  

后向引用

分组后,从左至右以(作为分组标志,默认从1开始作为组号递增,后向引用用于重复搜索前面某个分组匹配的文本

\b(\w+)\b\s+\1\b - 可以匹配类似"go go"(其中"\1""go")、"cmd   cmd"(其中"\1""cmd"),但不能匹配"cmd cmdd""123 234"

当然可以自己指定子表达式(某个分组)的组名,使用(?<Word>\w+)(?'Word'\w+),这样相当于将子表达式\w+命名为Word了,反向引用语法为\k<word>,这样上面那个例子可以写为

\b(?<cmd>\w+)\b\s+\k<cmd>\b

其实组号分配并没那么简单,组号0代表整个正则表达式,组号分配时会扫描表达式两遍,第一遍只给未命名组分配,第二遍只给命名组分配

零宽断言

类似于\b^$用于匹配一个位置,并且应该满足一定条件(断言)

零宽度正预测先行断言

(?=exp) - 匹配满足表达式之前的位置

\b\w+(?=ing\b) - 匹配一个以"ing"结尾的单词的前面部分

零宽度正回顾后发断言

(?<=exp) - 匹配满足表达式之后的位置

(?<=\bre)\w+\b - 匹配一个以"re"开头的单词的后面部分(?<=\s)\d+(?=\s) - 匹配两端都是空格字符的一串数字

零宽度负预测先行断言

表达式\b\w*q[^u]\w*\b本来只是想确定这个单词中含有’q’且后面不是’u’,但是[^u]必须匹配上一个字符,因此这一串不能匹配上”aiq”这种以’q’结尾的单词,却能匹配上”aiq be”这种两个单词以空格分开且前一个单词结尾是’q’的字符串,如果只用之前所说的方法,又要写上一长串的分枝了
(?!exp) - 匹配不满足表达式之前的位置

\d{3}(?!\d) - 匹配一串数字的最后三个数字\b((?!abc)\w)+\b - 匹配一个不包含"abc"子字串的单词\b([^q\s]*q(?!u)[^q\s]*)+\b - 就解决上面那个问题了

零宽度负回顾后发断言

(?<!exp) - 匹配不满足表达之后的位置

(?<![a-z])\d{7} - 匹配7个连续的数字,且第一个数字前不是小写字母(?<=<(\w+)>).*(?=<\/\1>) - 匹配不包含属性的简单HTML标签内里的内容(例如<b>123</b>中的123)  

注释

(?#comment) - 最好启用忽略模式里的空白符,这样表达式中可以添加任意的空格、换行字符,且#后面直到换行之前的都将被当作注释,例如之前(?<=<(\w+)>).*(?=<\/\1>)可以写为

(?<=    # 断言要匹配的文本的前缀<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签))       # 前缀结束.*      # 匹配任意文本(?=     # 断言要匹配的文本的后缀<\/\1>  # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签)       # 后缀结束

分组语法整理

下面整理以上常用的分组语法(其中exp代表表达式)

  • (exp) - 匹配exp,并捕获匹配得到的文本到自动命名的组内
  • (?<name>exp) - 匹配exp,并捕获匹配得到的文本到自主命名为name的组内
  • (?:exp) - 匹配exp,但不捕获文本,也不分配组号
  • (?=exp) - 匹配满足表达式之前的位置
  • (?<=exp) - 匹配满足表达式之后的位置
  • (?!exp) - 匹配不满足表达式之前的位置
  • (?<!exp) - 匹配不满足表达式之后的位置

限定符的贪婪与懒惰

  • 贪婪 - (默认)匹配尽可能多的字符
  • 懒惰 - 匹配尽可能少的字符,在限定符后添加? (*?+???{n,m}?{n,}?)
现有字符串aababa.*b - 匹配得到aababa.*?b - 匹配得到aab和ab

处理选项

  • IgnoreCase - 忽略大小写
  • Multiline - 多行模式,使得^$也匹配\n\r的前后位置
  • Singleline - 单行模式,使得.与所有字符匹配,包括\n
  • IgnorePatternWhitespace - 忽略非转义空白,并启用#注释
  • ExplicitCapture - 显式捕获,仅捕获已被显式命名的分组

平衡组/递归匹配

考虑到有嵌套关系的层次结构,例如xx <aa <bbb> <bbb> aa> yy这个字符串怎样匹配到最外层的<>所含内容
以下是.Net Framwork支持的语法结构

  • (?'group') - 把捕获的内容命名为group并压入堆栈(Stack)
  • (?-group) - 从堆栈顶弹出名为group的捕获内容,若堆栈为空,则此次分组匹配失败
  • (?(group)yes|no) - 如果堆栈上存在以group为名的捕获内容,则匹配yes部分的表达式,否则匹配no部分的表达式
  • (?!) - 由于没有后缀表达式,试图匹配总是失败
<[^<>]*(((?'Open'<)[^<>]*)+((?'-Open'>)[^<>]*)+)*(?(Open)(?!))><                         #最外层的左括号    [^<>]*                #最外层的左括号后面的不是括号的内容    (        (            (?'Open'<)    #碰到了左括号,在黑板上写一个"Open"            [^<>]*        #匹配左括号后面的不是括号的内容        )+        (            (?'-Open'>)   #碰到了右括号,擦掉一个"Open"            [^<>]*        #匹配右括号后面不是括号的内容        )+    )*    (?(Open)(?!))         #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败>                         #最外层的右括号

js中运用正则表达式

RegExp对象

js中正则表达式对象,通过下面两种方式可以创建

var re = new RexExp(str, attr) // str是正则表达式字符串,attr是可选参数var re = /str/attr // str是正则表达式,用两个/包围,后面attr是可选参数

可选参数(修饰符)

  • i - 忽略大小写敏感
  • g - 执行全局匹配
  • m - 执行多行匹配

常用的是g,比如用/\d+//\d+/g去匹配字符串1a2b3d4c,前者只能匹配到一个结果['1'],后者可以匹配到四个结果['1', '2', '3', '4']

可以使用正则的函数

以下样例中用 re表示正则表达式,用s表示字符串

s.match(re)

匹配字符串,返回匹配结果

s.search(re)

返回匹配上的第一个字串的偏移量

s.replace(re, text)

将匹配结果替换为其他文本

s.split(re)

将匹配的子串作为分隔符,返回分割后的数组(此函数无视g修饰符,默认全文替换)

re.exec(s)

对字符串查找,返回找到的子字符串和偏移量(此函数无视g修饰符,只返回第一个结果)

re.test(s)

检测字符串,仅当完全匹配上时返回true


资料整理

正则表达式30分钟入门教程
在线正则表达式测试
正则表达式_百度百科
js正则函数match、exec、test、search、replace、split使用介绍集合
JavaScript RegExp 对象

0 0
原创粉丝点击