Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
12
返回列表 发新帖
楼主: 爱疯

[已解决]正则问题 - 零宽度负预测先行断言一例

[复制链接]
发表于 2012-2-24 16:02 | 显示全部楼层
围观学习

点评

俺也是  发表于 2012-2-24 16:04
回复

使用道具 举报

 楼主| 发表于 2012-2-24 16:16 | 显示全部楼层
本帖最后由 爱疯 于 2012-2-24 16:29 编辑

想知道错误的原因。

红字体表示匹配值
绿字体表示预测
黄填充表示查找范围



第1次匹配:x = "100斤苹果 100元,30斤梨 60元,5斤香蕉 8.5元"

第2次匹配:x = "100斤苹果 100,30斤梨 60元,5斤香蕉 8.5元"

第3次匹配:x = "100斤苹果 100元,30斤梨 60元,5斤香蕉 8.5元"

第4次匹配:x = "100斤苹果 100元,30斤梨 60,5斤香蕉 8.5元"

第5次匹配:x = "100斤苹果 100元,30斤梨 60元,5斤香蕉 8.5"



为什么第1次和第2次不是同一标准,第3次和4次也不是同一标准?

点评

依贪婪匹配 原则,先匹配到最长的数字段,再判断后面的是否为非斤。再往次长的数字段进行匹配判断。  发表于 2012-2-24 16:46
回复

使用道具 举报

发表于 2012-2-24 16:34 | 显示全部楼层
本帖最后由 liuguansky 于 2012-2-24 16:41 编辑

{:1812:}贪婪匹配明白吗?
这个什么断言什么的,我的理解是
比如这个pattern"\d+\.?\d*(?!斤)"

\d+\.?\d*他先搜索最大的匹配段
如果后面是斤,那么再是减长度段匹配段,再看后面是不是斤
比如这样的文本"我是你你你你你你你“
pattern是".+(?!你|$)"
这个时候他最开始是匹配到我是你你你你你你,后面是你,不符合,再匹配到我是你你你你你,后面是你,不符合。。。。
因为+的贪婪性。
而pattern是".+?(?!你|$)"
文本为"我你你你你你你你你是你"
先匹配到我,而后面是你,不符合,再匹配到我你,后面是你,不符合。。。直到
我你你你你你你你你,符合要求。因为+?的懒惰性。
试试这段代码吧:

  1. Sub Test()
  2.     Dim regex As Object, matchs As Object, match As Object
  3.     Dim x As String, y As String, z As String
  4. '    x = "我你你你你你你你你你是你"
  5. '    y = ".+?(?!你|$)"
  6.     x = "我是你你你你你你你你你你"
  7.     y = ".+(?!你|$)"
  8.     Set regex = CreateObject("VBScript.RegExp")
  9.     With regex
  10.         .Global = True
  11.         .Pattern = y
  12.         MsgBox .Execute(x)(0)
  13.     End With
  14. End Sub

复制代码

回复

使用道具 举报

 楼主| 发表于 2012-2-24 16:48 | 显示全部楼层
本帖最后由 爱疯 于 2012-2-24 16:50 编辑

刚发了最佳,我又想起了 ..... 起因是想知道为什么不是3个价格的数字,我还没理解清楚啊{:201:}

点评

看我的点评,和贪婪懒惰匹配的例子,应该可以理解吧。  发表于 2012-2-24 17:01
回复

使用道具 举报

 楼主| 发表于 2012-2-24 17:31 | 显示全部楼层
本帖最后由 爱疯 于 2012-2-24 18:14 编辑

我现在,又清晰了。看说的对不对?


1、解释12#
如果不好理解12#,可把x的值换下

  1. Sub Test2()
  2.     Dim regex As Object, matchs As Object, match As Object
  3.     Dim x As String, y As String, z As String
  4.     x = "1斤苹果 2元,3斤梨 4元,5斤香蕉 6元"
  5.     y = "\d+\.?\d*(?!斤)"
  6.     Set regex = CreateObject("VBScript.RegExp")
  7.     With regex
  8.         .Global = True
  9.         .Pattern = y
  10.         Set matchs = .Execute(x)
  11.         Debug.Print "值", "位置", "长度"
  12.         For Each match In matchs
  13.             Debug.Print match.Value, match.firstindex, match.Length
  14.         Next
  15.     End With
  16. End Sub
复制代码
即所有数字都只有1位,这样负预测,看似可得到“3个价格的数字”了,但这是有隐患的,不准确的,有条件的 ------ 数字必须只1位。当换成12#那样,隐患就显现出来了。理由如7#和8#。


2、13#例子
我简化了例中的值,只为好数(那么多你你你。。。。。眼都花了),我觉得理解了这样,其它就能理解了。
  1. Sub Test1()
  2.     Dim regex As Object, matchs As Object, match As Object
  3.     Dim x As String, y As String, z As String
  4.     x = "abcdee"
  5.     y = ".+(?!e)"
  6.     Set regex = CreateObject("VBScript.RegExp")
  7.     With regex
  8.         .Global = True
  9.         .Pattern = y
  10.         MsgBox .Execute(x)(0)
  11.         MsgBox .Execute(x).Count
  12.     End With
  13. End Sub
复制代码
为什么结果仍是"abcdee"呢?
除^、$、\b外,当零度断言时,“位置”(^、$、\b)也将参入预测。(从13#例子中发现的)

首先,".+(?!e)"是贪婪模式。于是先考虑所有字符。"abcdee"后不是e而是$(字符串末尾,只是一个位置,但也被用来预测),符合条件,所以"abcdee"是匹配值。尽管"abc"也符合,但贪婪模式追求尽可能长。

当y = ".+(?!e|$)"时,分支决定.+。分支左边产生匹配值"abc"后,就不再查找了(尽管分支右边"abcdee"也符合,但分支总是优先考虑靠左的)



回复

使用道具 举报

发表于 2012-2-24 18:05 | 显示全部楼层
我认为因为这个叫零宽断言,是没有长度,只是确认一个位置[就是不在匹配结果中显示的],所以^$\b这样匹配一个位置的也是OK的
回复

使用道具 举报

 楼主| 发表于 2012-2-24 18:14 | 显示全部楼层
liuguansky 发表于 2012-2-24 18:05
我认为因为这个叫零宽断言,是没有长度,只是确认一个位置[就是不在匹配结果中显示的],所以^$\b这样匹配一 ...

不大理解这句的意思
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-6-4 11:11 , Processed in 0.293371 second(s), 15 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表