ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: liu-aguang

[原创] 正则表达式入门与提高---VBA平台的正则学习参考资料

    [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-6-11 17:01 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:文本处理和正则
本帖最后由 香川群子 于 2014-6-11 17:06 编辑

单词边界\b \B 的组合使用例子:


er.jpg

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 17:12 | 显示全部楼层
本帖最后由 liu-aguang 于 2014-6-15 21:28 编辑

     ()捕获性括号(…)与非捕获性括号(?:…).
     1.捕获型括号(….)
     前面已经多次遇见过捕获性括号”(…)”, 总结前面使用圆括号有二个理由:
     1)    分组,标明量词的作用范围.或限制多选结构,标明选择符”|”的作用范围.
     例:一文本中,有多行文本,提取行全部以”AA”开头的连续3行.
    正则表达式:
    (^AA.*\n){3}
    ^AA       锁定行特征,即行开始处有字符AA;
   .*        匹配行中其它字符至换行符,英文句点”.”是不能匹配换行符的;
   \n        匹配换行符;
   ^AA.*\n    匹配一个完整行;
   (^AA.*\n){3} 用()分组标明后面量词{3}的作用范围,即行重复3次.
   2)    捕获文本,将括号内容的内容保存在特殊变量中.
   在VBA中,捕获性括号保存的内容有三种方式引用:
   (1)  在Replace方法中通过$1,$2…方式引用;
   (2)  在正则表达式中,通过\1,\2…方式引用.
   (3)  可以用匹配对象的Submatches集合索引号提取其内容.
    3)    关于重复分组
   如果在分组的结束之后放一个量词,那么整个分组就会被重复.如(abc){3}与abcabcabc是相同的.
   那么最后捕获性括号捕获的内容是什么呢?
   例:正则表达式
   (\d\d){1,3}
   目标文本:123456
    最后匹配结果是123456.$1的值,即捕获性括号捕获到的内容是56.你可以编制代码测试,用submatches属性提取该值验证.得到这个结果的原因是:
分组的匹配在每次引擎退出该分组的时候被捕获,并会覆盖该分组在之前匹配的任何文本.(\d\d){1,3}会匹配一个包含2个,4个或6个数字的字符串.引擎会退出该分组3次.当这个正则表达式匹配到123456的时候,捕获分组中保存的是56,因为该分组的最后一次循环存储的是56.另外两次匹配12和34被覆盖了.
   2.非捕获型括号(?:…)
   捕获性括号保存内容时,是会付出处理成本的.所以,如果只需要让它起分组作用,而不必保存之中内容.正则表达式提供了一个非捕获性括号的字符序列:(?:….),在形式上比捕获性括号多一个”?:”,并紧跟在左括号之后,它们是一个整体.
   例:
   (?:中国|China)
   (?:.*)
   使用非捕获性括号可提高一定的匹配效率,特别是在使用循环的时候.
   再次指出的是,虽然环视中也有圆括号,但在那里是非捕获性的.
   
    ()抑制量词的贪婪性: ?

  前面已经知道,所有量词都是贪婪的,或称之为匹配优先的.他们总是匹配尽可能多的字符.下面例子可以了解什么是贪婪:
  目标文本:This is a <EM>first</EM> test
  要求:匹配提取标签<EM></EM>
  正则表达式:
   <.*>
  代码:
Sub test()
    Dim mh, s$
    s = "This is a<EM>first</EM> test"
    WithCreateObject("vbscript.regexp")
        .Pattern = "<.*>"
        .Global = True
        Set mh = .Execute(s)
    End With
    MsgBox mh(0)
End Sub
讨论:
   在正则表达式中,使用了量词"*".它表示可匹配0个或多个字符.执行该代码结果显示:<EM>first</EM>.为什么不是我们希望的<EM>或</EM >结果呢?下面分析它的匹配过程:
   当用正则表达式"<.*>"作用于目标文本时,首先用"<"去目标文本中尝试,结果在"标签"后面找到了"<";紧接着开始在下一个位置尝试”.*”,"."可匹配任意非换行符,"*"可以表示可以连续0次或多次.由于量词"*"匹配是匹配优先的,当匹配模式”.*”时,它会匹配至行的末尾,直到遇到换行符为止.下来该尝试表达式中的">"了,结果余下的字符是换行符,不能匹配字符”>”,在此匹配失败;
     在原理中我们会讲到,这时引擎会回退,直至回退到右边第一次出现”>”字符,匹配成功.最后报告成功匹配结果:<EM>first</EM>
    为了解决这类问题,正则引入了一个元字符”?”,将它紧跟在量词之后,如”.*?”,则可抑制量词的贪婪性.让它变成忽略优先量词.忽略优先量词总是匹配尽可少的字符
    同上例,正则表达式修改为:
      <.*?>
    其它代码不变,最后结果显示:<EM>,得到了我们希望的结果.(提示:从效率上看,本例用正则表达式”<[^>]*>”效率更高.其原因会在”原理篇”中会谈到)
上面的例子告诉我们,在匹配优先的量词后,紧跟一个”?”,则变成了”忽略优先量词”.它们总是匹配尽可少的字符.再举一例,在字符串“oooo”中,“o+?”只匹配单个“o”,而“o+”匹配所有“o”

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 17:37 | 显示全部楼层
香川群子 发表于 2014-6-11 16:10
(七)在哪里?

应该是【十六进制转义:\xnum (num是一个十六进制数)】吧。

谢谢提醒,不小心搞掉了.

TA的精华主题

TA的得分主题

发表于 2014-6-11 17:56 | 显示全部楼层
香川群子 发表于 2014-6-11 11:26
\b 和 \B

begin 的首字母 b

求教香川群子:
没看出execute()的区别。
好像replace()替换后是整体读取。
而execute()不能直接读取,读取是一个集合体,必须要遍历,才能读取其中的一个元素,或一组元素。
如下面2个程序:
  1. Sub a1()
  2. Dim regx As Object
  3. Set regx = CreateObject("vbscript.regexp")
  4. Dim str As String
  5. str = "12,3张山乡,BCD中心8.32学校—wanglei教师,meiABnv456良东"
  6. Dim s
  7. With regx
  8. .Global = True
  9. .Pattern = "[^\d]+"
  10. matc = .Replace(str, "")
  11. MsgBox matc
  12. End With
  13. End Sub

  14. Sub a2()
  15. Dim regx As Object
  16. Set regx = CreateObject("vbscript.regexp")
  17. Dim str As String
  18. str = "12,3张山乡,BCD中心8.32学校—wanglei教师,meiABnv456良东"
  19. Dim s
  20. With regx
  21. .Global = True
  22. .Pattern = "[\d]+"
  23. Set matc = .Execute(str)
  24. 'MsgBox matc
  25. For Each s In matc
  26. MsgBox s
  27. Next
  28. End With
  29. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2014-6-11 20:32 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
收藏,学习了~~~

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 21:57 | 显示全部楼层
     如果你已经读到了这里,那么恭喜你.你应该有很厚的正则功底了.
     尽管现在的你可以用正则来处理一些文本工作,但难免给人以花架子的印象.因为也许你用正则完成的任务,远不如用VBA自身函数或方法处理来得简洁快速.正则是用来处理,VBA难以为任的工作.所以,你需要进一步深入下去.
                                     第二篇 元字符(序列)进阶篇
   
一、元字符与字符集
     为了能在计算机中存储,处理和显示字符,在计算机初期出现了ASCII编码系统,它是用一系列代码表示字符,例如:十进制数65代表字符A.ASCII代码表中共有256个字符(包括扩展代码表), 它主要用于显示现代英语和其他西欧语言.随着计算机的发展,为了处理显示其它国家或地区的文字,又出现了很多地区性编码系统,如汉字编码GB 2312-80.地区性代码在电脑中的处理容易出现兼容性问题,于是相关国际组织制定了一个称之为Unicode的字符编码系统. Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求;Unicode定义了大到足以代表人类所有可读字符的字符集.
     字符编码是一个很大的课题,它不是正则研究的范畴.这里提到它,目的是提醒你在使用正则元字符(序列)表示字符时,需要注意它们的使用范围,正则表达式是在英文语系下诞生的,所以很多元字符(序列)可能只适合于ASCII代码表字符集.很多正则教程的默认语境也是英语环境下的表述.为此总结如下:
捕获.PNG

  说明:表中结论适合VBscriptJavaScript正则.在一些高版本的Java, .Net等语言中,正则有很大发展.不仅增加了更多的元字符种类,而且扩展了原有元字符的特性,”\d”还可以匹配非英文数字.如可以匹配全角的数字;”\b”也可以处理Unicode字符集等等.
   二、^$的位置到底在哪里
   当正则对象的Multiline属性为False(默认值),脱字符^与美元符$的意义是明确的,即分别表示文本开始和结束位置.
   而当Multiline属性为True,情况变得不那么简单了.特别是在匹配多行文本时,如果不仔细搞清楚它们的意义,就会遇到麻烦.
   先来看的定义, 不同操作系统对文本文件行结束符有不同定义.看到一种说法:Windows下按Enter键是 \n\r,Unix下是\n,Mac下是\r,MS的系统中纯文本格式按一个回车键是输入了两个字符,一个回车一个换行。在LINUX系统中则只是一个回车.
但现实是:在用VBA正则处理文本行的实践中,我们发现,无论是从文本文件中读出的字符串,word文档读出的字符串,或其它方式提供的字符串,一个文本行,往往结尾有\r\n\n\r的情况.
   本人通过实践发现,VBA中正则对行的理解是根据\n\r来确定.总结如下:
   “^”:
   只要行尾出现\r\n\r\n,那么就会在文本行开始处创建一个”^”.所以无论行结束符是\r\n,或是\n,或是\r,那么行开始处一定有一个”^”位置符.
   “$”:
   只要行尾出现\r\n,那么就会在\r\n字符前面紧挨着创建一个”$”位置.所以,如果行结尾符是\r\n两个字符组成的,那么,就会创建两个”$”位置.
   另外,无论文本结束处有无\r\n,^$是始终存在的.它代表文本的开始和结束位置.
   所以,在处理多行文本时,应用锚点^$,尤其是应用$,应该注意文本行结束处到是什么字符.
   MultilineTrue的前提下,如果要匹配连续多行文本,下列正则表达式就可能出问题:
   (^.*$){1,5}
   1.  假如文本行的结束符是”\r”,那么,该表达式就会匹配整个文本.因为”.”可以匹配回车符,”*”是匹配优先的.
   2.  假如文本行的结束符是”\r\n”,那么,该表达式只能匹配到一行内容,尽管文本有多行.这是因为上面说到的原因,在这种情况下,一行中有两个结束符.
   在匹配多行文本时,最好使用下面的方式:
   (^.*?(?:\r?\n|\r)){1,5}
   (^[^\r\n]+(?:\r?\n|\r)){1,5}
   当然,也可以事先测试一下文本的结束符是什么,后面不用选择结构.



补充内容 (2016-6-8 08:16):
处理多行文本整体时,如果Multiline=Ture,那么在每一个\r或\n的后面都有一个"^";在每一个\r或\n的前面都有一个$.

TA的精华主题

TA的得分主题

发表于 2014-6-11 23:12 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-12 08:53 | 显示全部楼层


三、字符组中元字符转义规则
    前面已经知道,在正则表达式中,表示元字符的字面意义时,往往需要用反斜线”\”转义.那么,在普通字符组中,表示元字符的字面意义时,如何处理呢?
    普通字符组中表示元字符的字面意义有自己的规则,总结如下:
        1.    在字符组中需要转义的元字符:
                  \       ]      [      ^     -
    例:[\\|\]],可匹配字符”\””]””|”.
    在上面五个需要转义的字符中,除反斜杠外其它四个字符在某些位置上也可不必转义,例如: [][^-] ,可分别匹配它们四者之一.虽然如此,建议使用以上五个字符时都进行转义,让代码更清晰.
        2.    字母数字字符如果在字符组中使用反斜线转义,要么出现错误,要么创建一个正则表达式记号.如把”\b”放入字符组中[\b],它表示匹配一个退格符(\x8)
        3.    表示字符的元字符序列如\n,\w,在元字符中是不能转义的.它们意义与在字符组外是一致的.:[\n\x20]可匹配一个换行符或空格.
        4.    表示位置,数量或控制的元字符(序列),放入字符组中,不再有原来意义.,”^”紧跟在字符组的”[“,表示否定字符组,放在字符组的其它位置,它表示匹配一个字面上脱字符;”$”放入字符组中也是表示字面字符”$”.
      :正则表达式:
       [*+^$|(){}?]
  可以匹配下列字符之一:* ,+ ,^ ,$ ,| ,( ,) ,{ ,} ,?
         5.    英文双引号无论在字符组内外,都要用重复的双引号转义.[“”]匹配一个双引号(”).

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-12 09:23 | 显示全部楼层
本帖最后由 liu-aguang 于 2014-6-12 09:26 编辑

  四、字符组与多选结构”|”
    在某些情况下,普通字符组与”|”匹配效果是一样的,
      [abc]a|b|c
    都是表示匹配字符ab c
    而更多的情况是差异极大::
     [中国|成都]
     (中国|成都)
    前者表示匹配字符//|//五个字符之一 ;后者表示匹配连续字符串中国成都.”
    它们两者的区别:
       1.    多选结构允许子表式表示一个更复杂的字符串,而普通字组只能表示一个字符.
       2.    即使多选结构的子表达式是单个字符的情况,两者的匹配机理也是不一样的.大多数正则引擎会对字符组提供非常好的优化,使用垂直竖线的多选结构要求引擎使用在计算上代价很高的回溯算法,而字符组则只使用非常简单的搜索算法.

     结论:如果匹配是多个字符之一最好选择字符组方式,而如果要匹配多个字符串之一就只能用多选结构方式了.

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-12 10:13 | 显示全部楼层
本帖最后由 liu-aguang 于 2014-6-12 13:57 编辑

   五、否定顺序环视与否定字符组
     看一个例子:
      (?!u)
      [^u]
    前者是否定顺序环视,表示该位置之后不能匹配字符”u”;后者是否定字符组,表示匹配一个非”u”字符.现在我们用下列两个正则表达式分别作用于目标文本的每个单词,观察匹配结果:
    目标文本:
Iraqi
Iraqian
Miqra
Qasida
Qintar
Qoph
Zaaqqum
Iraq
     正则表达式:
       Q(?!u)
       Q[^u]
     选项:设置IgnoreCasetrue
     下面是结果列表:
捕获.PNG

      可出看出两者的特点:
        q(?!u)表示只要字符q后面不跟着字符u,匹配则成功.它有两种情况,一是后面跟着一个不是u的字符,二是q后面不存在任何字符(iraq).
      另外从匹配结果再次看出,环视是不消耗字符的,即环视中子表达式匹配的结果(u),并不会出现在最终的匹配结果中.
        q[^u]表示字符q后面必须跟着一个不是u的字符,才会匹配成功.可见[^u]虽然是否定字符组,但它要匹配一个字符是肯定.也就是说否定字符组表示的是匹配一个未列出的字符,而不仅仅是不要匹配列出的字符




补充内容 (2016-6-8 08:23):
列表中Qintar和Qoph,的匹配结果是大写Q.表中有笔误.----正则并不能改变文本的字母大小写.

评分

1

查看全部评分

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

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-25 15:53 , Processed in 0.038931 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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