Hom's Blog


正则表达式

正则表达式: regexp; regex;

正则表达式是进行字符匹配的功用, 在搜索中很常用. 例如在unix命令grep, sed, awk, find中都可以支持正则表达式, 而脚本语言使用正则表达式进行爬虫等更是常事. 正则表达式一般有这几个功能:

  • 测试字符串内的模式. 测试该字符串是否合法.例如ip地址测试.
  • 搜索甚至替换字符串.
  • 获取指定模式字符串. 在特定区域内找到指定模式字符串, 从而进一步分析.

基本匹配

元字符和字符集

  • 具体字符: 明确匹配
  • . 除了\n外任意一个字符,要包含\n需要(.|\n)
  • [a0-9] 字符集, 可用-表范围(原-需转义)
  • [^abc] 字符集不包含abc. ^在字符集中为反义的意思, 反义还有如\d反义\D
  • \ 转义字符,对.*?+()\|等转义
  • ^匹配输入字符串开头,multiline属性可以使其匹配多行.
  • $ 匹配输入字符串末尾,multiline属性可以使其匹配多行.
  • \b 匹配单词边界(就是空白和标点位置罗),如er\b 对于hiver,而非verb
  • \B 非单词边界,如er\B 对于verb,而非hiver
  • \d数字 [0-9]
  • \D 非数字[^0-9]
  • \w 任何单词字符,包括下划线 [0-9a-zA-Z_]
  • \W 非单词字符,即[^0-9a-zA-Z_]
  • \n,\r,\f,\t,\v 匹配换行符,回车符,换页,制表,垂直制表符.
  • \s任何空白字符, 等价于[ \f\n\r\t\v]
  • \S 任何非空白字符,等价于[^ \f\n\r\t\v]

分支选择: 多种情况

  • abc|bcd 两者其中之一的匹配,遵循优先权法则.
  • a(bcd|hij)z 使用括号划分分支更有效!

数量限定: 跟在字符后面代表数量限制

  • 不加限定符 有且只有一个
  • + 1个或多个
  • ? 不多于1个(0或1个)
  • * 任意个(0或1或多个)
  • {n} 数量精确n个
  • {n,} 匹配数量不少于n(>=n).{1,}相当于+
  • {n,m} 匹配数量不少于n不多于m.

贪婪与懒惰: 跟在数量限定后, 最长匹配还是最短匹配

  • 贪婪 : 默认情况下尽可能多的匹配,例如a.*b 对aabab是匹配aabab.
  • 懒惰 : 使用?在匹配之后, 表示尽可能少的匹配,如a.*?b对aabab匹配aab(1-3)和ab(4-5). 懒惰的使用如*?,+?,??,{n,}?,{n,m}? 几种情况.
  • 最早匹配原则 : 最先开始的匹配拥有最高优先权,此原则高于贪婪和懒惰.所以上例匹配aab而不是ab(2-3).

分组

分为捕获性分组和不捕获分组:

捕获性分组

向后引用: 使用括号, 定义作为一个组, 可以被后续引用

  • (exp) : 匹配exp的内容并归入自动命名的组, 一般组从1开始.
  • (?<Word>exp)(?'Word'exp) : 将匹配内容归入名为Word的组.
  • (\1)以及(\k<Word>): 将之前匹配的组里的内容进行引用,此处引用自动命名的组1和自定义命名的组Word.

PS: 分组编号实际进行两轮: 首先对无自定义的组进行编号, 再对有别名的组进行编号, 实际有别名的组的编号均大于其余没有别名的组.

不捕获性分组

取消括号分组歧义

  • (?:exp): 非获取匹配, 即不作为分组,不储存,不分组序号. 用途在arriv(?:e|ing)中因为要做分支不得不用()但又避免进行分组.

零宽断言: 用于表达位置匹配,如^$/b等作用用于定位, 不会被作为匹配内容.

  • (?=exp): 断言自身出现的位置的后面能匹配表达式exp,如\b\w+(?=ing\b)可以匹配singing的sing
  • (?<=exp): 断言自身出现的位置的前面能匹配表达式exp,如(?<=\bre)\w+\b匹配reading的ading
  • (?!exp): 断言自身出现的位置的后面能匹配表达式exp
  • (?<!exp): 断言自身出现的位置的前面能匹配表达式exp

注释

(?#comment) 注释,如(?#这匹配string)

优先权

\> (),(?:), (?=), [] > *+?{n}{n,}{m,n}>^$中介字符>|

其实正则表达式比一般的搜索匹配差异是:

  • 贪婪和懒惰: 最长匹配和最短匹配
  • 分组和向后引用: 将之前一个匹配作为一个组, 方便后面调用.
  • 表达式位置匹配(零宽断言): 这部分是使用正则式来匹配位置, 而不是作为匹配内容, 十分方便用于定位.
  • 更多的元字符式样,如常用的\d, \w, \s.
  • 限定数量方式更多, 比一般使用?* 更多了{n,m}等的使用.
  • 匹配分支, 一般搜索匹配支持[0-9]这种是单字符分支, 这里支持匹配式分支

###例子

(\d{1,3}\.){3}\d{1,3} # IP地址格式匹配

<a[^>]+> #匹配用尖括号括起来的以a开头的字符串。

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)  #任意IP(<256)

(?<=<(\w+)>).*(?=<\/\1>)    #匹配不包含属性的简单HTML标签内里的内容,注意后面实际是</组1>

再议分组

Update: 2015.12.20

分组是正则表达式一个十分重要的特色. 其实零宽断言也是一种分组, 只是不把匹配内容作为匹配输出罢了. 分组并不是说把匹配的几个放到一个组里, 而是说某种匹配作为一个组, 这个匹配可以用于后续再使用. 另外, 分组还可以通过非捕获性来实现一些特殊功能.

捕获性分组

捕获性分组就是把匹配的内容储存到指定组(自动命名或者给定命名), 以后可以用于向后引用前面某个组的内容(引用分组).

捕获性分组就是()内的匹配, 或者给定组名的(?<name>exp)(?'name'exp). 或者引用前面内容的引用分组(\1)(\k<name>)

例如abacab中使用(a\w)\w*(\1)可以捕获abacab (组为(ab,ab))而不是abac(因为使用了引用上一个分组, 所以限定了后一个分组的匹配内容)

非捕获性分组

非捕获性分组主要是为了实现某些功能, 并非为了向后引用. 一个是位置限定, 一个相当于取消括号引起的歧义.

位置限定: 零宽断言

  • 零宽度正预测先行断言(positive lookahead assertion) (?=exp) (看后面的字符匹配, ->)
  • 零宽度正回顾后发断言(positive lookbehind assertion) (?<=exp) (看前面的字符匹配, <-)
  • 零宽度负预测先行断言(negative lookahead assertion) (?!exp) (看后面的字符不匹配, !->)
  • 零宽度负回顾后发断言(positive lookbehind assertion) (?<!exp) (看前面的字符不匹配, !<-)

取消括号歧义

  • (?:exp) : 可以取消括号带来的分组歧义, 像go(?:to|ing), 如果是go(to|ing)会把这里作为一个分组进行处理. 例如”goto detroid for going happy”, 前者在python的groups()返回(), findall中返回[goto, going]; 后者在groups()返回(goto,) findall中返回[to, ing]. 后者只会匹配一个组, 返回第一个匹配.

注释

  • (?#comment) 就是给自己看的罗.


◆ 本文地址: http://platinhom.github.io/2015/06/10/regexp-re/, 转载请注明 ◆

前一篇: MSYS输出中文到文件后无法提交到Github:UTF-8 error
后一篇: 蛋白等电点预测


Contact: Hom / 已阅读()
Source 类别: Coding  标签: Shell  Key