Confidential Property
Confidential Property 漫谈正则表达式 作者:Shy.Song 日期:2013-01-11 Confidential Property
Confidential Property 1 正则意义——搜索 工作中搜索一类文件 开发中找到一段代码 运维中查找一行日志 程序中匹配一个邮箱 *.doc 使用通配符可以查找指定模式内容 2012??.log Confidential Property
Confidential Property 1 最简单的正则 表达式: shy 能匹配的字符串: I am shy Luckyshy 123shy321 shy Confidential Property
Confidential Property 1 最简单的正则 我只想匹配自己: \bshy\b 匹配的结果: I am shy Luckyshy 123shy321 shy Confidential Property
Confidential Property 1 最简单的正则 \b \w \d () [] \W \s \S …… 这些符号的意义? (?>) (?<=) (?<!) \P{Inname} \p{Inname} 那这些又是什么? \x{4e00}-\x{9fa5} \x80-\xff 再看看这几个呢? Confidential Property
Confidential Property 2 正则表达式——字符 12个特殊的字符:$ ( ) * + . ? [ \ ^ { | 搜索它们自身需要在前面加反斜线来匹配。 字符组结构 [0-9] 数字0到数组9之间的任意一个 [a-z] 字母a到字母z的任意一个 [^shy] 除了字母shy的任意一个字符 [\u4e00-\u9fa5] 汉字中的任意一个汉字 [^a-z] 除了字母 a 到字母z的任意一个字符 [0-z] 匹配asicii码中0到z的其中一个字符 | 多选分支,或者关系 \1 \2 …反向引用 < (\w) >.*</\1> 引用第一个捕获组的结果,用于匹配html的闭合标签 ab|cd a(b|c)d 匹配abcd还是abd,acd Confidential Property
Confidential Property 2 正则表达式——模式 正则表达式定义:一个正则表达式通常被称为一个模式 (pattern),为用来描述或者匹配一系列符合某个句法规则的字符串。 高级正则离不开模式 . 除换行以外的其他任意字符 \s 空白字符 \S 除空白字符以外的任意字符 \w 字母、数字、下划线 \W 除了字母、数字、下划线以外的任意字符 \d 数字 0-9 \D 除了数字之外的任意字符 \b 单词边界 ^ 字符串的开始 $ 字符串结束 * 0到无数次 + 1到无数次 ? 0或者1次 {n} 重复N次 {n,} 重复至少N次 {n,m} n到m次 [] 字符组,字符范围 () 捕获组(子表达式) Confidential Property
Confidential Property 2 正则表达式——位置 “^”代表字符串的开头 “$”代表字符串的结尾 表达式: 表达式: ^Shy$ ^shy Shy$ 匹配: 匹配: shy is Shy. shy123Shy Shy is shy. Hi,shy! shy is Shy shy123Shy Shy is shy. Hi,shy! Confidential Property
Confidential Property 2 正则表达式——选择 方括号“[ ]”匹配指定一堆字符中的一个。 例子说明一切 ^[a-z]hy$ :why shy ^[A-Za-z]hy$ :why Why shy ^[uvwxyz]hy$ :why zhy yhy [a-zA-Z0-9_.-] :email [a-zA-Z0-9.-_] :not email(;?[]<…) Confidential Property
Confidential Property 2 正则表达式——重复 “+” 表示前一字符模式可以被重复1次或n次。 “*” 表示前一字符模式可以被重复0次或n次。 “{x,y}”表示前一字符模式可以被重复x到y次。 “{x,}” 表示前一字符模式可以被重复至少x次。 例子说明一切 ^go+gle$ :gogle google gooooooooooogle ^g[aeiou]+gle$ :gogle geagle gaeiouaeiougle ^go*gle$ :ggle google gooooooooooogle ^go{2,4}gle$ :google gooogle goooole ^go{2,}gle$ :google gooogle goooole gooooole … ^(shy )*is( shy)*$ :shy is shy shy shy Confidential Property
Confidential Property 2 正则表达式——分支 分支“|”用来指定几个规则只要匹配一个规则即成匹配。 例子说明一切 ^com$|^org$|^net$ :com org net ^shy.(com|org|net)$ :shy.com shy+net shy$net ^go*gle$ :ggle google gooooooooooogle ^go{2,4}gle$ :google gooogle goooole ^go{2,}gle$ :google gooogle goooole gooooole … ^(shy )*is( shy)*$ :shy is shy shy shy Confidential Property
Confidential Property 3 正则深入——起源 1940 神经学家研究出一种模型,认为神经系统在神经元层面上就是这样工作的。N年后数学家描述《正则集合(regular sets)》 1968年Ken Thompson的文章《regualr....》描述一种正则表达式编译器,该编译器生成IBM 7094的OBJECT代码,也诞生了他的qed,也就是后来的UNIX中ed编辑器的基础 ed没qed先进,他有个命令是这样 g/Regular Expresion/p 成为独立的工具grep(以及拓展的egrep) Confidential Property
Confidential Property 3 正则深入——流派 引擎类型 程序 DFA awk(多数版本)、egrep(多数版本)、flex、lex、Mysql 传统NFA GNU Emacs、JAVA、GREP、less、more、PREL、PHP、Python、ruby、sed、vi POSIX NFA mawk DFA/NFA混合 GNU awk、gun grep/egrep DFA: 文本向导引擎。 不允许回溯,不具备反向引用,不可以捕获子表达式。 NFA: 正则向导引擎。(猴急的) 贪婪的,正则优先(更长匹配未被发现,jane|janet两种解决办法) Confidential Property
Confidential Property 3 正则深入——贪婪 “+*?{x,y}” 这些都是贪婪的象征。 “?” 尽可能少的,非贪婪模式。 “+” 贪婪到底,没有退让。 让我们用例子说话 Confidential Property
Confidential Property 3 正则深入——?特殊 (?: 取消捕获分组( (a)\1 ) (?> 取消分组捕获,阻止回溯( (?>a*)a aaa) (?# 注释(正则也有注释!) (?= 肯定型顺序环视 (?<= 肯定型逆序环视 (?! 否定型顺序环视 (?<! 否定型逆序环视 <div>shy</div> (?<=<div>)\w+(?=</div>) Confidential Property
Confidential Property 3 正则深入——组成 正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的;如果子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配结果中,那么就认为这个子表达式是零宽度的。 占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配 字符0 字符1 cf 位置0 位置1 位置2 Confidential Property
Confidential Property 3 正则深入——流程 正则的匹配过程,通常情况下都是由一个子表达式(可能为一个普通字符、元字符或元字符序列组成)取得控制权,从字符串的某一位置开始尝试匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的。如正则表达式: (子表达式一)(子表达式二) 假设(子表达式一)为零宽度表达式,由于它匹配开始和结束的位置是同一个,如位置0,那么(子表达式二)是从位置0开始尝试匹配的。 假设(子表达式一)为占有字符的表达式,由于它匹配开始和结束的位置不是同一个,如匹配成功开始于位置0,结束于位置2,那么(子表达式二)是从位置2开始尝试匹配的。 而对于整个表达式来说,通常是由字符串位置0开始尝试匹配的。如果在位置0开始的尝试,匹配到字符串某一位置时整个表达式匹配失败,那么引擎会使正则向前传动,整个表达式从位置1开始重新尝试匹配,依此类推,直到报告匹配成功或尝试到最后一个位置后报告匹配失败。 Confidential Property
Confidential Property 3 正则深入——流程 源字符串:abc 正则表达式:abc 匹配过程: 首先由字符“a”取得控制权,从位置0开始匹配,由“a”来匹配“a”,匹配成功,控制权交给字符“b”;由于“a”已被“a”匹配,所以“b”从位置1开始尝试匹配,由“b”来匹配“b”,匹配成功,控制权交给“c”;由“c”来匹配“c”,匹配成功。 此时正则表达式匹配完成,报告匹配成功。匹配结果为“abc”,开始位置为0,结束位置为3。 Confidential Property
Confidential Property 3 正则深入——流程 源字符串:abc 正则表达式:ab?c 量词“?”属于匹配优先量词,在可匹配可不匹配时,会先选择尝试匹配,只有这种选择会使整个表达式无法匹配成功时,才会尝试让出匹配到的内容。这里的量词“?”是用来修饰字符“b”的,所以“b?”是一个整体。 匹配过程: 首先由字符“a”取得控制权,从位置0开始匹配,由“a”来匹配“a”,匹配成功,控制权交给字符“b?”;由于“?”是匹配优先量词,所以会先尝试进行匹配,由“b?”来匹配“b”,匹配成功,控制权交给“c”,同时记录一个备选状态;由“c”来匹配“c”,匹配成功。记录的备选状态丢弃。 此时正则表达式匹配完成,报告匹配成功。匹配结果为“abc”,开始位置为0,结束位置为3。 Confidential Property
Confidential Property 3 正则深入——流程 源字符串:a12 正则表达式:^(?=[a-z])[a-z0-9]+$ 元字符“^”和“$”匹配的只是位置,顺序环视“(?=[a-z])”只进行匹配,并不占有字符,也不将匹配的内容保存到最终的匹配结果,所以都是零宽度的。这个正则的意义就是匹配由字母或数字组成的,第一个字符是字母的字符串。 Confidential Property
Confidential Property 4 正则升华——优化 例子 DB中有个字段使用了浮点数,需要程序处理。需求是保留小数点后面3位,如果最后一位是0,则保留两位。 字符例子:15.214123、37.500232、154.356 目的: 15.214 37.50 表达式:? (\.\d\d[1-9]?)\d* $1 为什么 (\.\d\d[1-9]?)\d+ $1 Confidential Property
Confidential Property 4 正则升华——习惯 具体说来,就是谨慎用点号这样的元字符,尽可能不用星号和加号这样的任意量词。 只要能确定范围的,例如\w,就不要用点号;只要能够预测重复次数的,就不要用任意量词。 表达式:<div>([a-z0-9])+</div> 字符串:<div>……</div> 1W个字符 引擎会捕获多少个组呢? 说得狠一点,“滥用点号、星号和加号甚至括号是不环保、不负责任的做法”。 Confidential Property
Confidential Property 4 正则升华——高手 Confidential Property
Confidential Property The End Confidential Property