免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
11 [报告]
发表于 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
12 [报告]
发表于 2008-04-16 14:15 |只看该作者

回复 #9 churchmice 的帖子

其实我不理解的是最后的返回结果

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

论坛徽章:
0
13 [报告]
发表于 2008-04-16 14:24 |只看该作者
原帖由 churchmice 于 2008-4-16 12:25 发表

你咋知道第一句里面返回两个值呢?
...


$#line = 1 哦

论坛徽章:
0
14 [报告]
发表于 2008-04-16 14:28 |只看该作者
原帖由 andy820303 于 2008-4-16 14:15 发表
其实我不理解的是最后的返回结果

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

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

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
15 [报告]
发表于 2008-04-16 14:31 |只看该作者
原帖由 andy820303 于 2008-4-16 14:15 发表
其实我不理解的是最后的返回结果

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


因为(one)会把(one)变成一组..(one)* 自动匹配 0个以上的one....也就是one, oneone,oneoneone,都匹配....
不管有没有给//g都一样..

楼上已经解释的很清楚了.....

论坛徽章:
0
16 [报告]
发表于 2008-04-16 14:38 |只看该作者
我还不确定是否完全理解了apile兄的意思。

不过我可以理解这个匹配,所有的内容都被匹配上了,不过我想楼主的意思应该也是想问:为什么得到的结果只有最后的onE呢?

论坛徽章:
0
17 [报告]
发表于 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
18 [报告]
发表于 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
19 [报告]
发表于 2008-04-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 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.

很精彩阿,churchmice 兄看得太仔细了,但是这种逆向的匹配说起来还是很别扭的:(one)*匹配后得到的竟然是最后一个onE,为什么要这么些呢?

论坛徽章:
0
20 [报告]
发表于 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 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP