正则表达式——献给2013的葬礼
时间2013.12.29 地点:软件大楼211 —————————————————————————————————————————— 一、前言2013年就那么可心里默数的几十个小时留下,没想默数着让它过完期待那么光明的一天,黑夜给了我黑色的眼睛,我用来寻找光明,等天明,太阳升起,若在是舞池中央最好。 这篇文章是一篇正则表达式入门级别的科普,若真的想入门,此处无门。 在材料院的设备改造项目里,我们已经用到牛逼哄哄的正则表达式,主要用于实验记录的查询,如下所示:
平时我们在文本编辑器里比如word,text等的查找与替换功能也恰是正则表达式的功劳,玩Linux的大神们应该知道grep命令,全称是Global Regular Expression Print,是一个强大的文本搜索工具,凭借正则表达式搜索文本,并把匹配行打印出来,正则表达式概念的普及正是始于此,当然这点应用只是皮毛。有些问题不深究往往被小看,有些问题深究却是死胡同,世界因为有问题才留给我们机会,不是吗?瞎闹与折腾,现在发现傻子其实最幸福,智商越高脑壳越疼,情商越高心越疼。 —————————————————————————————————————————— 二、问世间正则表达式为何物,直叫人生死相许在很多场合,我们需要查找出符合某一特定规则的字符串,这种需求有很多很多,比如Google浏览器的查找功能,在比如计算机的搜索查找功能,而正则表达式正是用于描述这一特定规则的工具。我们说某个字符串匹配某个正则表达式,即该字符串的部分满足于正则表达式给出得条件。是不是,因为这个工具,许多事情变得便捷,世界因为正则表达式而变得美丽,有阳光或许感觉到冷。 ——————————————————————————————————————————
|
. (点号,12K的火眼金睛才看得清) | 匹配除换行符以外的任意字符 |
w | 匹配字母或数字或下划线或汉字 |
s | 匹配任意的空白符,包括制表符、空格 |
d | 匹配数字 |
b |
匹配单词的开始或结束 |
^ |
匹配字符串的开始 |
$ |
匹配字符串的结束 |
* |
重复零次或更多次 |
+ |
重复一次或更多次 |
? |
重复零次或一次 |
{n} |
重复n次 |
{n,} |
重复n次或更多次 |
{n,m} |
重复n到m次 |
下面还给个反义表
W |
匹配任意不是字母,数字,下划线,汉字的字符 |
S |
匹配任意不是空白符的字符 |
D | 匹配任意非数字的字符 |
B |
匹配不是单词开头或结束的位置 |
[^x] |
匹配除了x以外的任意字符 |
[^aeiou] |
匹配除了aeiou这几个字母以外的任意字符 |
举例:
baw*b ——匹配步骤:1.开始处以字母a开头,2.跟任意的字母、数字、下划线或汉字字符,3.字符数的目任意,4.结束。
连起来说就是:我们想要匹配以a开始,后面紧跟数目任意的某字符这样一个字符串。
d+ ——匹配步骤:1.数字一个,2.数目为一个或一个以上
连起来说就是:我们想要匹配某个数字的任意个数串(当然至少1个)
^d{6,10}$ ——匹配步骤:1.一个数字字符开始,2.个数为6到12个
所以有些网上要你填写身份证号码或者电话号码或者QQ号码,当位数不对时马上就会给出提示,就是这样来得。
那么我们现在还来说说^d{6,10}$与单纯d{6,10}的区别:
^d{6,10}$ 匹配的是以一个数字开始,整个字符串是6到10个数字组成的字符串,比如:12345678
而d{6,10} 匹配的是字符串中含有6到10个连续数字组成的串即OK,比如: hu12345678nan
前者是标记有开始和结束,要求严格,后者是只要包含即可。
所以我们可知道,正则表达式所说的单词即连续个字符组成的字符串。不一定有含义,只要连续。
五、转义
和编程语言一样,元字符都有特殊的含义,如果我们要匹配元字符,这就需要转义,我们一如既往地选择来取消这些字符的特殊含义,比如: . * 等,这就不多描述了,业界通用,但还要记住一点,如果在编程语言中实现,我们还要转义一次,因为这些符号在编程语言里又有特殊含义,又要取消一下特殊含义,现在麻烦来了,拿 *来说: 1.先是在正则表达式里我们要转义: * 2.然后在编程语言里为了让上面这个是普通含义,我们给他一个 于是成了 * 然而到这一步我们还只是让它在程序里是个 * 3.为了然 *不具备特殊含义我们还要一个 于是整个普通*的实现就是: * 若是的表示为: \ 看得好揪心 好在C++11(别的语言我不知道)里有原始字符串变量一说,于是转义一次就OK,比如我要匹配 空格、换行符、回车符、和反斜杠,按往常要这么写: ( |n|r|\) ——说明:1.(后紧跟一个空格字符,2.晓得为什么是n而不是n吗? 在C++11里,我们可以这样写:R"~( |n|r|)~" ——漂亮吧,~是边界符,可不要,也可换成其它,小括号是必须的,里边包含原始字符串。 六、多字符匹配
说道这,我们已经能解决好多问题了,给定目标的查找都不是问题了,但还是不够用,社会太复杂了,比如你想找出某个文本里的所有元音字母:a e i o u ,办法很简单,把它们列在方括号里即可:[aeiou] ,这样我们就能匹配任何一个这样的元音字母,注意一个的含义,apple并不是它能匹配得到的,要么a 要么e 要么i等等。 也可以指定范围[0-9]匹配0到9的一个数字,同d,同理注意只是一位的数字,来个123连续数位的无能为力。 再比如[a-zA-Z] 能匹配a到z和A到Z范围内的所有字母 再看个复杂的(?0d{2}[) -]?d{8} 1. (?说明右括号可有可无 2.然后是数字0 3.d{2}说明跟了2个数字 4.[) -]?说明)或者空格或者-可有可无 5.d{8}说明后面是8个数字 于是乎可匹配 (010)88886666 010-888886666 010 88886666 (010-88886666(这个匹配并不是我们想要的,下面会讨论如何解决)之流的电话号码 要说明的是(和)也是元字符,所以也用消除特殊含义,使之正常。 七、分支条件
上面匹配得到了一个不合理的匹配,用分支条件可解决这个问题,即使用 | 把不同的几部分分离开来 0d{2}-d{8}|0d{3}-d{7} 匹配: 0XX-XXXXXXXX 或者 0XXX-XXXXXXX d{5}-d{4}|d{5} 匹配: XXXXX-XXXX 或者 XXXXX 这里要注意的是分支条件的顺序,如果满足前一条件了,后面就不管了,比如这里写成d{5}|d{5}-d{4} 就有问题了。 八、分组
括号()用于标记子表达式,子表达式也称捕捉组,好诡异的名字,括号括起来之后括号里的部分就是一个整体,你可视为单个字符,而括号里边我们也可以进行局部操作。比如 (d{1,3}.){3}d{1,3} 1.(d{1,3}.) 说明是一个1到3位的数字,后面跟一个.(刚开始我一直这样理解,认为b是一位数字,然后再重复1到3次,如此便是2,22,222之辈,后面想通了应该这样理解,{1,3}是作用于d的,而不是作用于d的一个实例,也就是说,展开后有1到3个d,嗯,展开,先展开表达式,这样就好理解多了是不是) 2.(d{1,3}.){3} 即如果把小括号里的部分看成一个整体,那么我们在这里重复这样操作3次,比如可得到49.123.82. 3.(d{1,3} 在前面基础上加上一个三位数。 擦,这就是传说中的IP匹配,但 256.257.455.520等不合理的IP也匹配进去了,所以我们还要继续加约束条件: ((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?)。 九、贪婪与懒惰
贪婪匹配即尽可能多的执行字符匹配,比如a.*b,意义上是匹配a开始,b结尾的字符串,当碰到aabab时,贪婪匹配会匹配完整即aabab,可不是aab(懒惰匹配),那么怎么进行懒惰匹配呢,那就是在重复符号(* + ? {...})后追加?,即a.*?b,如此为尽可能少地匹配字符重复。 ——————————————————————————————————————————
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
十、葬礼
那一刻,
不等花鸟鱼闲,
那一天,
那一夜,
不知南星疲倦,
那一月,
不畏风雨,
那一年,
不寻罗绮逅风情啊,
那一世,
不问今生是何年,
那一瞬,
不觉梦里绕魂牵,
静默默念,