Further Study of Rugular Expresions

2016-02-19 11:03 8 1 收藏

只要你有一台电脑或者手机,都能关注图老师为大家精心推荐的Further Study of Rugular Expresions,手机电脑控们准备好了吗?一起看过来吧!

【 tulaoshi.com - Web开发 】

小弟便兴起了学一学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. belvisb (将elvis视为一整体的字查找,如elvis、elvis乎略字符大小写时)
“b”在re中有特别的意思,在上述的例子中所指的就是字的边界,所以belvisb用b把elvis的前后边界界定出来,也就是要elvis这个字。
  假设要将同一行里elvis后接有alive的文字符串找出来,此时就会用到另外二个特别意义的字符”.”及”*”。”.”所代表就是除了换行字符的 任意字符,而”*”所代表的是重复*之前项目直到找到符合re的字符串。所以”.*”所指的就是除了换行字符外的任意数目的字符数。所以查找同一行里 elvis后接有alive的文字符串找出来,则可下如3之re。
  3. belvisb.*baliveb (查找elvis后面接有alive的文字符串,如elvis is alive)
  用简单之特别字符就可以组成功能强大的re,但也发现当使用越来越多的特别字符时,re就会越来越难看得懂了。
再看看另外的例子
  组成有效的电话号码
  假使要从网页上收集顾客格式为xxx-xxxx的7位数字的电话号码,其中x是数字,re可能会这样写。
  4. bddd-dddd (查找七位数字之电话号码,如123-1234)
  每一个d代表一个数字。”-”则是一般的连字符号,为避免太多重复的d,re可以改写成如5的方式。
  5. bd{3}-d{4} (查找七位数字电话号码较好的方法,如123-1234)
  在d后的{3},代表重复前一个项目三次,也就是相等于ddd。
  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. baw*b (查找a开头的字,如able)
  这re描述要查找一个字的开始边界(b),再来是字母”a”,再加任意数目的字母数字(w*),再接结束这个字的结束边界(b)。
  7. d+ (查找数字字符串)
  “+”和”*”非常相似,除了+至少要重复前面的项目一次。也就是说至少有一个数字。
  8. bw{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. bw{5,6}b (查找五个或六个字母数字字符的字,如as25d、d58sdf等)
  11. bd{3}sd{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. bd{5}-d{4}bbd{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]d25[0-5][01]?dd?).){3}(2[0-4]d25[0-5][01]?dd?) (寻找网络地址)
  有没有发觉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+)bs*1b (寻找重复字,此处说的重复是指同样的字,中间有空白隔开如dog dog这样的字)
(w+)会抓取至少一个字符的字母或数字的字,并将它命名为群组1,之后是查找任意空格符,再接和群组1相同的文字。
  如果不喜欢群组自动命名的1,也可以自行命名,以上述例子为例,(w+)改写为(?wordw+),这就是将所抓取的群组命名为word,backreference就要改写成为kword
21. b(?wordw+)bs*kwordb (使用自行命名群组抓取重复字)
  使用括号还有许多特别的语法元素,比较通用的列表如下:
  抓取(captures)
  (exp) 符合exp并抓取它进自动命名的群组
  (?nameexp) 符合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. bw+(?=ingb) (字尾为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. bw*q[^u]w*b (一个字,其字母里有q但接下来的字母不是u)
  这样的re会有一个问题,因为[^u]要对应一个字符,所以若q是字的最后一个字母,[^u]这样的下法就会将空格符对应下去,结果就有可能会符合二个字,比如说”iraq haha”这样的文字。使用negative lookaround就能解决这样的问题。
  27. bw*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 #符合所抓取群组1之字符串,也就是前面小括号的html标签
  ) #结束查找字尾
  寻找最多字符的字及最少字符的字(greedy and lazy)
  当re下要查找一个范围的重复时(如”.*”),它通常会寻找最多字符的符合字,也就是greedy matching。举例来说。
  32. a.*b (开始为a结束为b的最多字符的符合字)
  若有一字符串是”aabab”,使用上述re所得到的符合字符串就是”aabab”,因为这是寻找最多字符的字。有时希望是符合最少字符的字也就是 lazy matching。只要将重复前述项目的表加上问号(?)就可以把它们全部变成lazy matching。因此”*?”代表的就是重复任意 次数,但是使用最少重复的次数来符合。举个例子来说:
  33. a.*?b (开始为a结束为b的最少字符的符合字)
  若有一字符串是”aabab”,使用上述re第一个所得到的符合字符串就是”aab”再来是”ab”,因为这是寻找最少字符的字。
  *? 重复任意次数,最少重复次数为原则
  +? 重复至少一次,最少重复次数为原则
  ?? 重复零次或一次,最少重复次数为原则
  {n,m}? 重复至少n次,但不超过m次,最少重复次数为原则
  {n,}? 重复至少n次,最少重复次数为原则
还有什么没提到呢?
  到目前为止,已经提到了许多建立re的元素,当然还有许多元素没有提到,下表整理了一些没提到的元素,在最左边的字段的数字是说明在expresso中的例子。
  # 语法 说明
  a bell 字符
  b 通常是指字的边界,在字符组里所代表的就是backspace
  t tab
  34 r carriage return
  v vertical tab
  f from feed
  35 n new line
  e escape
  36 nnn ascii八位码为nnn的字符
  37 xnn 十六位码为nn的字符
  38 unnnn unicode为nnnn的字符
  39 cn control n字符,举例来说ctrl-m是cm
  40 a 字符串的开始(和^相似,但不需籍由multiline选项)
  41 z 字符串的结尾
  z 字符串的结尾
  42 g 目前查找的开始
  43 p{name} unicode 字符组名称为name的字符,比如说p{lowercase_letter} 所指的就是小写字
  (?exp) greedy次描述,又称之为non-backtracking次描述。这只符合一次且不采backtracking。
  44 (?x-yexp)
  or (?-yexp) 平衡群组。虽复杂但好用。它让已命名的抓取群组可以在堆栈中操作使用。(小弟对这个也是不太懂哩)
  45 (?im-nsx:exp) 为次描述exp更改re选项,比如(?-i:elvis)就是把elvis大乎略大小写的选项关掉
  46 (?im-nsx) 为之后的群组更改re选项。
  (?(exp)yesno) 次描述exp视为zero-width positive lookahead。若此时有符合,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。
  (?(exp)yes) 和上述相同但无no次描述
  (?(name)yesno) 若name群组为有效群组名称,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。
  47 (?(name)yes) 和上述相同但无no次描述
  结论
  经过了一连串的例子,及expresso的帮忙,相信各位大大对re有个基本的了解,网络上当然有许多有关于re的文章,如果各位大大有兴趣http://www.codeproject.com 还有许多关于re的相关文章。

来源:http://www.tulaoshi.com/n/20160219/1596455.html

延伸阅读

经验教程

518

收藏

6

精华推荐

微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部