免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5523 | 回复: 6
打印 上一主题 下一主题

正则表达式的细节 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-09-04 17:39 |只看该作者 |倒序浏览
在搞清楚所述及的问题之前
首先明确一下什么是匹配
匹配可以从两个方面来理解
1 一个正则表达式和一个字符串是否匹配
    在perl中 =~ 代表捆绑 也就是让正则表达式去匹配指定的字符串
    如果如果用匹配的符号形式来表现 对于 /regular/ =~ "string"  如果返回值为真 则说/regular/ 匹配了"string"
2 一个正则表达式不只可以匹配一个字符串
    例如  /a*b/   不仅可以匹配aaaab 还可以匹配aaaaaab     b 等
    这里所谓的“匹配”也是指  /a*b/ =~ aaaab   /a*b/ =~ b  返回值都是真
下面说说依次匹配
首先的一个问题是一个正则表达式的工作过程
举个例子
  1. $data is 192.168.0.1
  2. $data =~ /([0-9]*\.)([0-9]*.)([0-9]*\.)([0-9])/;
  3. $1 is 192.
  4. $2 is 168.
  5. $3 is 0.
  6. $4 is 1
  7. 这里
  8. /([0-9]*\.)([0-9]*\.)([0-9]*\.)([0-9])/  匹配了192.168.0.1
  9. 同时在这个较长的正则表达式子是由几个短的正则表达式组成的,这些短的在()中的正则表达式称为模式,大家对$1,$2,$3,$4的值的输出都非常理解
复制代码

下面再举一个例子
  1. $data =~ /([0-9]*\.)([0-9]*\.)*([0-9])/;
  2. $1 is 192.
  3. $2 is 0.
  4. $3 is 1
复制代码

这里有观点解释到这里([0-9]*\.) ([0-9]*\.) *([0-9])  红色部分"依次匹配" 了168.    0.       所以是0.   
这并不是很好理解
有证:
[quote]原帖由 "3x3eyes"]....匹配.168都还好理解所谓的依次匹配是什么意思,请各位帮忙[/quote 发表:

问题的关键是为什么这里的红色部分会去依次匹配168.     0.呢?regular 有这种依次匹配的机制吗 它在什么情况下会这样做 什么情况下不会这么做呢
下面我们通过一个例子来验证regular 会不会有这种依次匹配的机制
  1. $data =~ /([0-9]*\.)([0-9]*\.)([0-9])/;
  2. $1 is 192.
  3. $2 is 168.
  4. $3 is 0
复制代码

这里红色部分并没有去依次匹配168.  0. 而是直接匹配了168.  
为什么呢 看来 问题出现在* 上面
也就是当正则表达式是 $data =~ /([0-9]*\.)([0-9]*\.)*([0-9])/;   的时候  红色部分依次匹配了168.   0.   并最终把最后匹配的0.存到了分组2中
      当正则表达式是 $data =~ /([0-9]*\.)([0-9]*\.)([0-9])/;    的时候  红色部分就不再依次匹配了??  它就匹配168.  并把168存在分组2中 这是什么道理?  
正则表达式有一个引擎 引擎的工作原理细节没有找到相应文档 但是对于这种情况 可以试着解释为
  1. 对于 $data =~ /([0-9]*\.)([0-9]*\.)([0-9])/;
  2. 这时候对于模式1 模式2 模式3 他们没有机会选择  分别将各自匹配的 192.   168.   0  存在正则表达式的记忆体 \1 \2 \3中
  3. 而对于 $data =~ /([0-9]*\.)([0-9]*\.)*([0-9])/;
  4. 对于模式1  从左到右搜索$data 匹配了192.    把它存在了记忆体  \1中
  5. 对于模式2  从左到右搜索剩下的$data 部分  匹配了 168.  并把它存在了记忆体\2中
  6. 下面到了*  这里*代表 前面模式的0次或多次出现 虽然在功能上对于这个例子它等于([0-9]*\.)([0-9]*\.)([0-9]*\.)([0-9])/, 但是它并不等价于正则表达式/([0-9]*\.)([0-9]*\.)([0-9]*\.)([0-9])/ 。这时候仍然是模式2 去从左到右搜索$data剩余的字符串0.1  结果匹配了0.  由于仍然是模式2去匹配,所以0. 仍然存在记忆体\2中,冲掉了原来存在记忆体\2中的内容 下面([0-9])  匹配了1 并把它存在了记忆体\3中。
复制代码

看到这里,可以试着总结出正则表达式的引擎搜索机制:
  1. 1  如果在正则表达式中有模式 ,那么每个模式从左到右搜索要匹配的字符串,如果匹配成功,则把匹配的字符串存到相对应的记忆体中。
  2. 2  如果正则表达式中有下一个模式,那么这个模式将继续从左到右搜索没有被匹配的字符串 ,重复前面的步骤1的过程,匹配成功则立即停止,并把匹配的字符串存到相应的记忆体中。
  3. 3  如果在2中的模式后面出现了数量符* + ? ,形如:(模式2)*,则匹配过程变为:模式2仍然按照步骤1的过程匹配,匹配成功则停止。但是由于这时候在模式2后面出现了数量符 * ,则仍然由模式2去匹配字符串中没有被匹配的的部分,如果这时候出现了可以匹配多个字符串的情况,那么作后一次匹配成功的字符串被存放到了模式2对应的记忆体中(注意:中间匹配成功的并不是没有存,而是被后面匹配成功的覆盖了)。
复制代码

说到这里仿佛一切问题都得到了很好的解释
可是请看下面的例子
  1. $data = 192.168.0.1
  2. $data =~ /([0-9]*\.)([0-9]*\.)*([0-9]*\.)([0-9]*.)([0-9])/
  3. 按照上面的结论,大家不妨猜测一下\2的内容 ,也就是记忆体2中的值是什么
  4. 在没有看到答案之前,也许会有人猜测是0. 或者168.。
  5. 但是这里 \2的值是空值,*在这里是“0个”。
复制代码

由此可以得到:正则表达式并不是按照模式按照从左到右搜索,"一个正则表达式" 就是一段程序,一个正则表达式的匹配引擎机制应该是:尽量多的精确的去匹配目标字符串,至于它采取哪种策略实现这一过程,这也是在此抛砖引玉的目的所在。

论坛徽章:
0
2 [报告]
发表于 2005-09-05 09:19 |只看该作者

正则表达式的细节

望高手们出手指正

论坛徽章:
0
3 [报告]
发表于 2005-09-05 12:56 |只看该作者

正则表达式的细节

一不小心成了反面典型
不过,楼主,我还是认为shell是把所有模式里的RE全都解释了以后,用这整个RE去匹配的

很感激楼主的分析与讲解

论坛徽章:
0
4 [报告]
发表于 2005-09-05 15:08 |只看该作者

正则表达式的细节

好贴,收下

论坛徽章:
0
5 [报告]
发表于 2005-09-12 23:49 |只看该作者

正则表达式的细节

顶下

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
6 [报告]
发表于 2005-09-13 00:29 |只看该作者

正则表达式的细节

眼晕呀~~~~      

论坛徽章:
0
7 [报告]
发表于 2005-09-16 09:49 |只看该作者

正则表达式的细节

中文匹配该怎么办?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP