免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: sosogh
打印 上一主题 下一主题

m//在列表上下文中的返回值问题 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2008-04-16 10:04 |显示全部楼层
原帖由 andy820303 于 2008-4-16 09:05 发表
从后匹配?

还是没有理解!

  1. Mail:~# perl -e '$_="OneoNeonE";@line=m/(one)*/gi;print "@line\n"'  |cat -A
  2. onE $
复制代码

这句加不加/g都是一样的
因为你(one)*这个本身已经把$_的全部内容给匹配了,无所谓再次匹配,/g有没有都一样
你可以试着改成下面的样子就可以看出区别来了

  1. perl -e '$_="OneseehereoNeonE";@line=m/(one)*/gi;print "@line\n"'  |cat -A
复制代码

这个时候加不加/g就有区别了

论坛徽章:
0
2 [报告]
发表于 2008-04-16 12:25 |显示全部楼层
原帖由 sosogh 于 2008-4-15 23:42 发表


谢谢你的回复
()里为什么是onE?
第一句返回2个值,@line有2个元素

你咋知道第一句里面返回两个值呢?
照你这个写法,第一句返回的就只有一个值
因为你的(one)*, 意思是匹配0次或者多次的one,而*是贪婪匹配,也就是说它倾向于匹配多次,所以结果就是
(one)*匹配了$_的所有内容

你可以用非贪婪匹配
see

  1. <lig@romeo:~>$ perl -e '$_="oneoneone";@line = m /(one)*?/g; print "@line\n"'
  2. one  one  one
复制代码


当然这里的*?有点问题,因为*?倾向于不匹配(*代表0次或者1次),所以(one)*?其实在任何时候都是匹配成功的,这样就会产生死循环,所以这个时候起作用的是regex的引擎,是这个引擎使得匹配的位置bump along

更好的写法是将*?换成+?,当然在这里结果是一样的,但是内在的处理过程却是不一样的

论坛徽章:
0
3 [报告]
发表于 2008-04-16 14:28 |显示全部楼层
原帖由 andy820303 于 2008-4-16 14:15 发表
其实我不理解的是最后的返回结果

第一个例子中既然都匹配了,为什么返回的结果不是“OneoNeonE”呢?

丢脸了
发现你所说的问题所在了
see see再说
不好意思

论坛徽章:
0
4 [报告]
发表于 2008-04-16 14:59 |显示全部楼层
原帖由 andy820303 于 2008-4-16 14:15 发表
其实我不理解的是最后的返回结果

第一个例子中既然都匹配了,为什么返回的结果不是“OneoNeonE”呢?

我想我已经理解了
首先看一段perldoc
The "/g" modifier specifies global pattern matching--that is,
               matching as many times as possible within the string.  How it
               behaves depends on the context.  In list context, it returns a
               list of the substrings matched by any capturing parentheses in
               the regular expression.  If there are no parentheses, it
               returns a list of all the matched strings, as if there were
               parentheses around the whole pattern.

这段话的意思就是说m//g的返回值是由()捕获到的值,如果没有()的话则返回所有匹配的内容

你第一句话的错误就在于你用()把one给扩起来了,这样m/(one)*/g的返回值就只能是()捕获到的值,也就是说是one
你可以选用non capture parenthess,

  1. (?:one)*
复制代码

这样结果就是正确的

  1. <lig@romeo:~/chinaunix>$ perl -e '$_="OneoNeonE";@line=m/(?:one)*/gi;print "@line\n"'
  2. OneoNeonE
复制代码

[ 本帖最后由 churchmice 于 2008-4-16 15:00 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2008-04-16 15:07 |显示全部楼层
至于具体的匹配过程我是这样理解的,
1.一开始看到(one)*,所以整个$_都被匹配了,这个时候返回给@data的值是"onE",因为用了捕捉的(),所以m//g的返回内容是()中捕获的内容
2.由于整个m//g,所以引擎尝试再次匹配,由于(one)*也匹配最后的空字符(zero width match),所以这个时候返回给@data的是一个null
3.由于(one)*其实可以匹配无限次(因为它本来就匹配nothing),这样会造成死循环,引擎已经预料到这种情况,所以就退出


所以结果@data里面有两个元素,最后一个是没有初始化的元素(第二次匹配返回的null)


see

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. my $str = "OneoNeonE";
  5. my @data = $str =~ m/(one)*/gi;
  6. my $length = $#data;
  7. print "length is $length\n";
  8. print "$_\n" foreach @data;
复制代码

<lig@romeo:~/chinaunix>$ ./greedy
length is 1
onE
Use of uninitialized value in concatenation (.) or string at ./greedy line 8.

论坛徽章:
0
6 [报告]
发表于 2008-04-16 15:26 |显示全部楼层
原帖由 andy820303 于 2008-4-16 15:12 发表
The "/g" modifier specifies global pattern matching--that is,
               matching as many times as possible within the string.  How it
               behaves depends on the context.  In lis ...

post to Larry Wall
其实只要理解了正则引擎的backtrace(回朔),这样也是可以理解的
对于$_="OneoNeonE"
使用模式(one)*/i
1.正则引擎从字符串的头部开始
2.由于(one)*也匹配空,所以引擎创建 state1,这个state包含了匹配的内容,这里就是null
3.接着看到One,也匹配,所以引擎创建 state2,这个state包含了匹配内容 One
4.接着看到oNe,创建state3,包含匹配内容 oNe
5.看到onE,创建state4,包含匹配内容onE
6.这个时候(one)*整体匹配成功了,而且regex后面也没有其他需要继续匹配的东西,因而regex引擎认为整体匹配已经成功,所以没有必要backtrace了,这个时候最新的state,也就是state4里面存放的内容是onE,所以这个结果就被返回了


这些state都是存放在类似堆栈的结构中,state1在stack的底部,state4在stack的顶部
如果regex是(one)*one的话由于(one)*匹配了所有内容导致后面的one无法匹配,因而要退栈,返回到state3,再尝试匹配,这个时候全局就匹配成功了,你可以试验一下,这个时候的返回内容就是oNe了

这就是backtrace的大致原理,当然实际中还有各种优化,远比这个复杂

[ 本帖最后由 churchmice 于 2008-4-16 15:28 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-04-16 15:45 |显示全部楼层
原帖由 andy820303 于 2008-4-16 15:37 发表
小弟对churchmice 的敬仰犹如滔滔江水啊!

不错,搂主这个问题提的真不错,学到很多东西。

请问churchmice 兄,这些内容是在哪儿看到的呢?

learning perl
mastering regular expression

论坛徽章:
0
8 [报告]
发表于 2008-04-20 08:23 |显示全部楼层
原帖由 sosogh 于 2008-4-20 02:14 发表


为什么第二句:
2.由于(one)*也匹配空,所以引擎创建 state1,这个state包含了匹配的内容,这里就是null


不是放到匹配过程的最后一步(作为第5点)而作为第2点?这个null不是由最后的空字符所引起的吗?

这里的1,2,3,4,5,6步的结果从大的方面来说只是进行了一次匹配(1,2,3,4,5,6只是具体的back trace的过程),匹配了"OneoNeonE",同时返回了onE
然后正则引擎看到/m修饰,再从前一次成功匹配的结尾,也就是$_的末尾尝试第二次的匹配,这个过程和前面的1,2,3,4,5,6类似,但是匹配到的结果是null,同时返回的也是null
然后引擎尝试再次匹配,但是上一次成功匹配的位置还是$_的结尾,这样下去会死循环,因而正则引擎便要跳出这个循环,所以不再进行匹配
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP