分享
 
 
 

正则表达式学习心得体会

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

Regular Expressions(正则表达式,以下用RE称呼)对小弟来说一直都是神密的地带,看到一些网络上的大大,简单用RE就决解了某些文字的问题,小弟便兴起了学一学RE的想法,但小弟天生就比较懒一些,总希望看有没有些快速学习的方式,于是小弟又请出Google大神,藉由祂的神力,小弟在网络上找到了Jim Hollenhorst先生的文章,经过了阅读,小弟觉得真是不错,所以就做个小心得报告,跟Move-to.Net的朋友分享,希望能为各位大大带来一丁点在学习RE时的帮助。Jim Hollenhorst大大文章之网址如下,有需要的大大可直接连结。

The 30 Minute Regex Tutorial By Jim Hollenhorst

http://www.codeproject.com/useritems/RegexTutorial.asp

什么是RE?

想必各位大大在做文件查找的时侯都有使用过万用字符”*”,比如说想查找在Windows目录下所有的Word文件时,你可能就会用”*.doc”这样的方式来做查找,因为”*”所代表的是任意的字符。RE所做的就是类似这样的功能,但其功能更为强大。

写程序时,常需要比对字符串是否符合特定样式,RE最主要的功能就是来描述这特定的样式,因此可以将RE视为特定样式的描述式,举个例子来说,”\w+”所代表的就是任何字母与数字所组成的非空字符串(non-null string)。在.NET framework中提供了非常强大的类别库,藉此可以很轻易的使用RE来做文字的查找与取代、对复杂标头的译码及验证文字等工作。

学习RE最好的方式就是藉由例子亲自来做做看。Jim Hollenhorst大大也提供了一个工具程序Expresso(来杯咖啡吧),来帮助我们学习RE,下载的网址是http://www.codeproject.com/useritems/RegexTutorial/ExpressoSetup2_1C.zip。

接下来,就让我们来体验一些例子吧。

一些简单的例子

假设要查找文章中Elvis后接有alive的文字符串的话,使用RE可能会经过下列的过程,括号是所下RE的意思:

1. elvis (查找elvis)

上述代表所要查找的字符顺序为elvis。在.NET中可以设定乎略字符的大小写,所以”Elvis”、”ELVIS”或者是”eLvIs”都是符合1所下的RE。但因为这只管字符出现的顺序为elvis,所以pelvis也是符合1所下的RE。可以用2的RE来改进。

2. \belvis\b (将elvis视为一整体的字查找,如elvis、Elvis乎略字符大小写时)

“\b”在RE中有特别的意思,在上述的例子中所指的就是字的边界,所以\belvis\b用\b把elvis的前后边界界定出来,也就是要elvis这个字。

假设要将同一行里elvis后接有alive的文字符串找出来,此时就会用到另外二个特别意义的字符”.”及”*”。”.”所代表就是除了换行字符的任意字符,而”*”所代表的是重复*之前项目直到找到符合RE的字符串。所以”.*”所指的就是除了换行字符外的任意数目的字符数。所以查找同一行里elvis后接有alive的文字符串找出来,则可下如3之RE。

3. \belvis\b.*\balive\b (查找elvis后面接有alive的文字符串,如elvis is alive)

用简单之特别字符就可以组成功能强大的RE,但也发现当使用越来越多的特别字符时,RE就会越来越难看得懂了。

再看看另外的例子

组成有效的电话号码

假使要从网页上收集顾客格式为xxx-xxxx的7位数字的电话号码,其中x是数字,RE可能会这样写。

4. \b\d\d\d-\d\d\d\d (查找七位数字之电话号码,如123-1234)

每一个\d代表一个数字。”-”则是一般的连字符号,为避免太多重复的\d,RE可以改写成如5的方式。

5. \b\d{3}-\d{4} (查找七位数字电话号码较好的方法,如123-1234)

在\d后的{3},代表重复前一个项目三次,也就是相等于\d\d\d。

RE的学习及测试工具 Expresso

因为RE不易阅读及使用者容易会下错RE的特性,Jim大大开发了一个工具软件Expresso,用来帮助使用者学习及测试RE,除了上面所述的网址之外,也可以上Ultrapico网站(http://www.Ultrapico.com)。安装完Expresso后,在Expression Library中,Jim大大把文章的例子都建立在其中,可以边看文章边测试,也可以试着修改范例所下的RE,马上可以看到结果,小弟觉得非常好用。各位大大可以试试。

.NET中RE的基础概念

特殊字符

有些字符有特别的意义,比如之前所看到的”\b”、”.”、”*”、”\d”等。”\s”所代表的是任意空格符,比如说spaces、tabs、newlines等.。”\w”代表是任意字母或数字字符。

再看一些例子吧

6. \ba\w*\b (查找a开头的字,如able)

这RE描述要查找一个字的开始边界(\b),再来是字母”a”,再加任意数目的字母数字(\w*),再接结束这个字的结束边界(\b)。

7. \d+ (查找数字字符串)

“+”和”*”非常相似,除了+至少要重复前面的项目一次。也就是说至少有一个数字。

8. \b\w{6}\b (查找六个字母数字的字,如ab123c)

下表为RE常用的特殊字符

. 除了换行字符的任意字符

\w 任意字母数字字符

\s 任意空格符

\d 任意数字字符

\b 界定字的边界

^ 文章的开头,如”^The'' 用以表示出现于文章开头的字符串为”The”

$ 文章的结尾,如”End$”用以表示出现在文章的结尾为”End”

特殊字符”^”及”$”是用来查找某些字必需是文章的开头或结尾,这在验证输入是否符合某一样式时特别用有,比如说要验证七位数字的电话号码,可能会输入如下9的RE。

9. ^\d{3}-\d{4}$ (验证七位数字之电话号码)

这和第5个RE相同,但其前后都无其它的字符,也就是整串字符串只有这七个数字的电话号码。在.NET中如果设定Multiline这个选项,则”^”和”$”会每行进行比较,只要某行的开头结尾符合RE即可,而不是整个文章字符串做一次比较。

转意字符(Escaped characters)

有时可能会需要”^”、”$”单纯的字面意义(literal meaning)而不要将它们当成特殊字符,此时”\”字符就是用来移除特殊字符特别意义的字符,因此”\^”、”\.”、”\\”所代表的就是”^”、”.”、”\”的字面意义。

重复前述项目

在前面看过”{3}”及”*”可以用来重复前述字符,之后我们会看到如何用同样的语法重复整个次描述(subexpressions)。下表是使用重复前述项目的一些方式。

* 重复任意次数

+ 重复至少一次

? 重复零次或一次

{n} 重复n次

{n,m} 重复至少n次,但不超过m次

{n,} 重复至少n次

再来试一些例子吧

10. \b\w{5,6}\b (查找五个或六个字母数字字符的字,如as25d、d58sdf等)

11. \b\d{3}\s\d{3}-\d{4} (查找十个数字的电话号码,如800 123-1234)

12. \d{3}-\d{2}-\d{4} (查找社会保险号码,如 123-45-6789)

13. ^\w* (每行或整篇文章的第一个字)

在Espresso可试试有Multiline和没Multiline的不同。

匹配某范围的字符

有时需要查找某些特定的字符时怎么辨?这时中括号”[]”就派上了用场。因此[aeiou]所要查找的是”a”、”e”、”i”、”o”、”u”这些元音,[.?!]所要查找的是”.”、”?”、”!”这些符号,在中括号中的特殊字符的特别意义都会被移除,也就是解译成单纯的字面意义。也可以指定某些范围的字符,如”[a-z0-9]”,所指的就是任意小写字母或任意数字。

接下来再看一个比较初复杂查找电话号码的RE例子

14. \(?\d{3}[( ] \s?\d{3}[- ]\d{4} (查找十位数字之电话号码,如(080) 333-1234 )

这样的RE可查找出较多种格式的电话号码,如(080) 123-4567、511 254 6654等。”\(?”代表一个或零个左小括号”(“,而”[( ]”代表查找一个右小括号”)”或空格符,”\s?”指一个或零个空格符组。但这样的RE会将类似”800) 45-3321”这样的电话找出来,也就是括号没有对称平衡的问题,之后会学到择一(alternatives)来决解这样的问题。

不包含在某特定字符组里(Negation)

有时需要查找在包含在某特定字符组里的字符,下表说明如何做类似这样的描述。

\W 不是字母数字的任意字符

\S 不是空格符的任意字符

\D 不是数字字符的任意字符

\B 不在字边界的位置

[^x] 不是x的任意字符

[^aeiou] 不是a、e、i、o、u的任意字符

15. \S+ (不包含空格符的字符串)

择一(Alternatives)

有时会需要查找几个特定的选择,此时”|”这个特殊字符就派上用场了,举例来说,要查找五个数字及九个数字(有”-”号)的邮政编码。

16. \b\d{5}-\d{4}\b|\b\d{5}\b (查找五个数字及九个数字(有”-”号)的邮政编码)

在使用Alternatives时需要注意的是前后的次序,因为RE在Alternatives中会优先选择符合最左边的项目,16中,如果把查找五个数字的项目放在前面,则这RE只会找到五个数字的邮政编码。了解了择一,可将14做更好的修正。

17. (\(\d{3}\)|\d{3})\s?\d{3}[- ]\d{4} (十个数字的电话号码)

群组(Grouping)

括号可以用来介定一个次描述,经由次描述的介定,可以针对次描述做重复或及他的处理。

18. (\d{1,3}\.){3}\d{1,3} (寻找网络地址的简单RE)

此RE的意思第一个部分(\d{1,3}\.){3},所指的是,数字最小一位最多三位,并且后面接有”.”符号,此类型的共有三个,之后再接一到三位的数字,也就是如192.72.28.1这样的数字。

但这样会有个缺点,因为网络地址数字最多只到255,但上述的RE只要是一到三位的数字都是符合的,所以这需要让比较的数字小于256才行,但只单独使用RE并无法做这样的比较。在19中使用择一来将地址的限制在所需要的范围内,也就是0到255。

19. ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) (寻找网络地址)

有没有发觉RE越来越像外星人说的话了?就以简单的寻找网络地址,直接看RE都满难理解的哩。

Expresso Analyzer View

Expresso提供了一个功能,它可以将所下的RE变成树状的说明,一组组的分开说明,提供了一个好的除错环境。其它的功能,如部分符合(Partial Match只查找反白RE的部分)及除外符合(Exclude Match只不查找反白RE的部分)就留给各位大大试试啰。

当次描述用括号群组起来时,符合次描述的文字可用在之后的程序处理或RE本身。在预设的情型下,所符合的群组是由数字命名,由1开始,由顺序是由左至右,这自动群组命名,可在Expresso中的skeleton view或result view中看到。

Backreference是用来查找群组中抓取的符合文字所相同的文字。举例来说”\1”所指符合群组1所抓取的文字。

20. \b(\w+)\b\s*\1\b (寻找重复字,此处说的重复是指同样的字,中间有空白隔开如dog dog这样的字)

(\w+)会抓取至少一个字符的字母或数字的字,并将它命名为群组1,之后是查找任意空格符,再接和群组1相同的文字。

如果不喜欢群组自动命名的1,也可以自行命名,以上述例子为例,(\w+)改写为(?<Word>\w+),这就是将所抓取的群组命名为Word,Backreference就要改写成为\k<Word>

21. \b(?<Word>\w+)\b\s*\k<Word>\b (使用自行命名群组抓取重复字)

使用括号还有许多特别的语法元素,比较通用的列表如下:

抓取(Captures)

(exp) 符合exp并抓取它进自动命名的群组

(?<name>exp) 符合exp并抓取它进命名的群组name

(?:exp) 符合exp,不抓取它

Lookarounds

(?=exp) 符合字尾为exp的文字

(?<=exp) 符合前缀为exp的文字

(?!exp) 符合后面没接exp字尾的文字

(?<!exp) 符合前面没接exp前缀的文字

批注Comment

(?#comment) 批注

Positive Lookaround

接下来要谈的是lookahead及lookbehind assertions。它们所查找的是目前符合之前或之后的文字,并不包含目前符合本身。这些就如同”^”及”\b”特殊字符,本身并不会对应任何文字(用来界定位置),也因此称做是zero-width assertions,看些例子也许会清楚些。

(?=exp)是一个”zero-width positive lookahead assertion”。它指的就是符合字尾为exp的文字,但不包含exp本身。

22. \b\w+(?=ing\b) (字尾为ing的字,比如说filling所符合的就是fill)

(?<=exp)是一个”zero-width positive lookbehind assertion”。它指的就是符合前缀为exp的文字,但不包含exp本身。

23. (?<=\bre)\w+\b (前缀为re的字,比如说repeated所符合的就是peated)

24. (?<=\d)\d{3}\b (在字尾的三位数字,且之前接一位数字)

25. (?<=\s)\w+(?=\s) (由空格符分隔开的字母数字字符串)

Negative Lookaround

之前有提到,如何查找一个非特定或非在特定群组的字符。但如果只是要验证某字符不存在而不要对应这些字符进来呢?举个例子来说,假设要查找一个字,它的字母里有q但接下来的字母不是u,可以用下列的RE来做。

26. \b\w*q[^u]\w*\b (一个字,其字母里有q但接下来的字母不是u)

这样的RE会有一个问题,因为[^u]要对应一个字符,所以若q是字的最后一个字母,[^u]这样的下法就会将空格符对应下去,结果就有可能会符合二个字,比如说”Iraq haha”这样的文字。使用Negative Lookaround就能解决这样的问题。

27. \b\w*q(?!u)\w*\b (一个字,其字母里有q但接下来的字母不是u)

这是”zero-width negative lookahead assertion”。

28. \d{3}(?!\d) (三个位的数字,其后不接一个位数字)

同样的,可以使用(?<!exp),”zero-width negative lookbehind assertion”,来符合前面没接exp前缀的文字符串。

29. (?<![a-z ])\w{7} (七个字母数字的字符串,其前面没接字母或空格)

30. (?<=<(\w+)>).*(?=<\/\1>) (HTML卷标间的文字)

这使用lookahead及lookbehind assertion来取出HTML间的文字,不包括HTML卷标。

请批注(Comments Please)

括号还有个特殊的用途就是用来包住批注,语法为”(?#comment)”,若设定”Ignore Pattern Whitespace”选项,则RE中的空格符当RE使用时会乎略。此选项设定时,”#”之后的文字会乎略。

31. HTML卷标间的文字,加上批注

(?<= #查找前缀,但不包含它

<(\w+)> #HTML标签

) #结束查找前缀

.*

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有