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 12:46 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:文本处理和正则
453563050 发表于 2014-6-11 12:01
不明觉厉,好好学习一下。谢谢楼主分享成果~
我就想搞懂几件事情
1.什么是正则

简要地说,【正则】是用来处理文字的。

【正则】 其实是 Regular Express 中 Regular 的中文翻译。

本意是规律的、正确的、或者是符合正确规则的……

也就是楼主说的:【为了高效处理各种复杂的文本字符对象,抽象地提炼出一个规律、规则、正则】
然后,使用专门的程序或脚本语言如 "VBScript.RegExp" ,
使用上述抽象的【正则表达式】来处理所有任意文本字符串,得到希望的结果。


问题3的回答:
怎么用需要你自己慢慢学习。学会了就能用了。
正则的使用有一定门槛,没有耐心、智商低的就永远学不好。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 13:04 | 显示全部楼层
453563050 发表于 2014-6-11 12:01
不明觉厉,好好学习一下。谢谢楼主分享成果~
我就想搞懂几件事情
1.什么是正则

看完第一章你就明白了。

TA的精华主题

TA的得分主题

发表于 2014-6-11 13:11 | 显示全部楼层
liu-aguang 发表于 2014-6-11 13:04
看完第一章你就明白了。

楼主是边写边发帖么……这很厉害。

语言虽然算不上幽默风趣,但非常简练精要。而且几乎毫无语病和错别字。

楼主的作文功底很好呢。

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 14:04 | 显示全部楼层
香川群子 发表于 2014-6-11 13:11
楼主是边写边发帖么……这很厉害。

语言虽然算不上幽默风趣,但非常简练精要。而且几乎毫无语病和错别 ...

谢谢美女夸奖!请多多指教!

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 14:23 | 显示全部楼层
本帖最后由 liu-aguang 于 2014-6-17 18:42 编辑

(前面第一篇的第一/二部分,概要阐述了正则表达式的基本思想,并对正则在VBA中的实现(也就是Regexp对象操作)作了详细讲解.接下来的第二至第六部分我们将集中介绍VBA中(本质上是Regexp对象中)可使用的全部元字符(序列),有的称为元字符的"特性",有的叫作正则"语法".反正它的基本属性就是用来描述字符的特殊字符.)
     三.正则元字符----字符表示法
     人类自然语言所用字符极其丰富多样,我们已经知道正则表达式是用元字符及它们的组合来描述这些字符以及这些字符组成的特定结构的.需要指出的是,正则没有统一标准,它是分流派的.在不同语言平台上(或同语言平台而版本不同),正则元字符的多少往往不同,同一元字符的特性也可能存在一定的差异.正是这个原因,在你参考各种正则资料的时候,尤其要注意这个问题.前面已经阐明,目前VBA平台上,用的是VBScript提供的正则对象,执行的是ECMA-262所规定的标准.
    VBscript提供的元字符可方便地描述ASCII码表中的字符集.ASCII码表基本上包括了英文语系所用的所有字符.(如果你不熟悉,可以上网查查,大体上了解有哪些字符).也支持代码点不超过四位十六进制数的Unicode表的字符集.这解决了包括汉字在内的世界各国的官方文字的表示问题.为方便用户在不同环境下使用,同一字符往往有多种等价表示方法.
    下面是对表示字符的元字符及序列的分类介绍:
    (一)对于一些常用的不可打印字符,规定了专用的元字符序列
    用正则表达式来描述一段字符串,即使它是看不见的,也必须毫无遗漏地表示出来.比如,空格,空白字符和一些不可打印字符,所以,在元字符(序列)中都有它们的表示方法.
捕获.PNG
   ()普通字符组:肯定字符组[a-z]及否定字符组[^a-z]
   肯定字符组表示方括号内列出的任意一个字符.否定字符组是在左方括号后紧跟着一个脱字符”^”,表示匹配括号内未列出的任一字符.:
捕获11.PNG




讨论:
   1.如果字符范围在ASCII码表或Unicode字符表中是连续分布的,可以只用起止字符表示范围,中间用”-“连接.
   2.用”-“连接的字符范围,前面必须是起点字符,如不能把[a-z]写为[z-a]
   3.字符组内的字符顺序无关紧要,如[^ieou]与[^eiuo]是一个意思.
   4.如果”-“字符中最左或最右位置,它表示匹配字面字符”-“.如[ieou-]
   5.如果”^”没有紧跟在”[“之后,它也只表示字面字符”^”.






评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 14:41 | 显示全部楼层
本帖最后由 liu-aguang 于 2014-6-17 18:57 编辑

  ()字符组缩略表示法
对于一些常用的字符类,正则提供了简略表示法:

捕获12.PNG
    提示:肯定类字符缩略表示法,只能表示ASCII码表中的字符,而该表中的否定元字符序列,它们可以匹配文本中unicode字符.
  实例:
  正则表达式              \W\W\s\w\w\w
  它表示匹配一个非单词字符,紧跟又是一个非单词字符,再是一个空格,最后连续三个单词字符.可以匹配:”正则 ABC”,”规则 1_3”.
  ()几乎能匹配任何字符的元字符:英文句点
  英文点号”.”可以匹配除换行符(\n)外的任意字符之一.它不限于ASCII码表中的字符,只要能显示于电脑上的字符都能匹配.VBA,英文句点等价于[^\n].
   ()控制字符表示法:\cChar
  ASCII码表中,十进制代码为1-26的字符全是控制字符,可以用”\c”连接字母A-Z之一来表示. \cA-\cZ分别表示代码为1-26的控制字符.”\cM”,表示回车符.
   ()ASCII码表中字符的八进制转义表示法:\num
   VBscript正则可用字符的八进制编码转义来表示ASCII字符:它的序列由反斜线和字符的八进制编码组成.例:
捕获13.PNG
  提示:八进制转义法表示字符范围:\0--\377,包括ASCII码表和扩展表中的256个字符.该表示法主要用于难以输入的字符.
  ()ASCII码表中字符的十六进制转义表示法: \xnum  
  一个小写的\X后跟两个大写十六进制数字可以匹配ASCII字符集中的一个字符.
捕获.PNG
  提示:可匹配范围\x00--\xFF,但一般用\x00--\x7F表示ASCII字符集中的前128个字符.\x80-\xFF(ASCII扩展码表字符),一般用Unicode代码点表示法替代.
   ()Unicode码表中字符的十六进制转义表示法:\unum
      Unicode码一般用称之为代码点来表示一个字符.它是一个十六进制数.
   正则表达式中,用“\u”序列后面紧跟字符unicode代码点(十六进制数)表示该字符.
:
捕获15.PNG
提示:
1.\unum表示法可表示代码点在U+0000--U+FFFF范围内的unicode字符.Unicode本身在发展中,已经出现超过4位的代码点,VBscript正则是不支持,但它们是很难遇到的字符.
2.用字符组[…]表示Unicode字符范围时,也可直接用表中起点字面字符与终点字面字符表示.比如大陆中文字符在Unicode表中,起始代码点是U+4e00,是表示中文字符”,终点代码点U+9fff,该代码点未定义,字在终点附近,所以我们也可以用”[-]”表示所有中文字之一.顺便提示一点,汉字在Unicode中的分布,基本无规律.不要想像"一",后面就是"二"等等.
3.有些流派的正则可以用Unicode的属性来方便表示不同类别的汉字或其它语言文字,但VBscript 5.5是不支持的.







TA的精华主题

TA的得分主题

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

   ()元字符字面字符表示法:转义符”\”
   正则表达式用了一部分字符作为元字符,那么怎样在正则表达式中表示这些元字符的字面字符呢?它提供了一个称为转义元字符,即反斜杠来表示.:表示字面点号可用”\.”;表示反斜杠的字面字符,”\\”表示.下面列举了如果匹配字面字符必须转义的元字符:
捕获16.PNG
提示:
     1.注意并没有包括”]”,”-“,”}”;
     2.普通字符组[…]内部,元字符的转义有自己的规则,在下一章专门介绍.
  例:正则表达式:
    \d\.\d
  可以匹配0.2,3.1….等小数.

()引用前面括号捕获的文本--反向引用  
  正则中,用形如\1,\2…的元字符序列表示前面捕获性括号内的字串(),”\1”叫反向引用.:
     (abc)\1
  可以匹配目标文本:abcabc,这里\1实际引用的是它左边括号中的内容”abc”.
          (abc)(defg)\2
  可以匹配目标文本:abcdefgdefg ,这里\2指的是从左至右第二个括号中的内容.
  实例:删除一段英文中重复的单词.
  目标文本:This this Is is an example.
  结果文本:this is an example
         正则表达式:
     (\w+)\s+\1
  代码:
Sub testrep()
    Dim reg, s$
    s = "This this is Is an exmapl"
    Set reg =CreateObject("vbscript.regexp")
    reg.Pattern = "(\w+)\s+\1"
    reg.Global = True
    reg.IgnoreCase = True
    s = reg.Replace(s, "$1")
    MsgBox s
End Sub
讨论:
  正则表达式中,”\w+”表示匹配连续出现的单词字符.在本例中,它会匹配至空格为止;”\s+”匹配一个或多个空格; “\1”它会匹配左边第一个出现的括号中的相同内容.所以,该正则会匹配诸如”1 1” “1111    1111”之类的文本.
  代码中Global属性设置为True,表示搜索所有匹配;IgnoreCase属性设置为True,表示忽略大小写,”this” ”THIS”视为同一单词.
  代码使用了正则对象的Repalce方法,$1替换找到的匹配. 这个例中,共找到两个匹配”This this””Is is”;$1在前面已经说过它保存的是第一个捕获性括号内的内容.在本例中分别是ThisIs.最终通过替换实现了删除重复单词的目的.
  VBA中使用反向引用要注意:
  1.    是表示八进制转义的字符还是反向引用?
  细心朋友已经发现,反向引用与字符的八制转义表示法,其结构是一样的.那么怎样区分它们呢?其规则是:
  “\num”:假如num是一个可以看作八进制的数字.
     如果num的值大于正则左前边捕获性括号个数,那么,它是一个八进制转义符;
  如果num的值小于或等于正则左前边捕获性括号个数,那么,它是一个反向引用;
  显然,如果它左前边没有捕获性括号,那么,它肯定是一个八进制转义符了.如果num数字中含有超过8,或9的数字,那么,它一定是反向引用.
  2.    \1,\2,…编号是根据前面左半圆括号从左至右出现的顺序确定的.



评分

4

查看全部评分

TA的精华主题

TA的得分主题

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

  四.正则元字符----字符()连续出现次数表示法  
  上一章介绍表示字符的元字符或序列都只代表一个字符.要表示连续多个字符,正则表达式提供了下表中的元字符(序列):
捕获.PNG
  讨论:
  1.这些元字符(序列)量词”,它作用于它前面紧挨的字符或字符串.作用的范围:可用()标示.如果没有(),那么它只作用前面紧挨的一个字符;如果要作用它前面多个字符,必须用()标明范围.:
捕获1.PNG






3.慎用可选项量词
  显然,上例中浮点数的正则不能匹配这样表示的浮点数如:”.123”.可能你已经想到用下列表达式了:
  \d*(\.\d+)?
  的确它能匹配所有形式的浮点数了.但是由于表达式中整数部分与小数部分都是可选的,这意谓着什么也不匹配,也能匹配成功.也就是说无论目标文本是空字符还是任意字符(串),正则引擎都会报告匹配成功(不过匹配结果都是空值).
  4.它们都是贪婪量词,即总是尝试匹配尽可能多的字符.比如:可选项量词"?" 它的下限是0即不匹配,上限是1. 如果有符合要求的字符(串),它则选择匹配一个字符(串),不会选择不匹配.

    例:正则表达式
  .*
  它总是匹配一行中换行符前所有的文本.
  实例:提取科室名
  目标文本:
  姓名:张三 科室:人事科(科长)
  姓名:李四 科室:保卫科(干事)
  正则表达式:
  科室:(.*)
  代码:
Sub testname()
    Dim reg, mh, s$
    s = "姓名:张三 科室:人事科(科长)" & vbCrLf & "姓名:李四 科室:保卫科(干事)"
    Set reg =CreateObject("vbscript.regexp")
    reg.Pattern = "科室:(.*)"
    reg.Global = True
    Set mh = reg.Execute(s)
    MsgBox mh(0).SubMatches(0)
    MsgBox mh(1).SubMatches(0)
End Sub

    讨论:
   当用"科室:(.*)"去匹配文本时,在第一行成功匹配到:"科室:"后,正则的(.*)部分将依次匹配到后面跟着的所有字符,直到英文句点不能匹配的换行符.所以括号捕获到的内容是:人事科(科长).
   而Global属性设置为true,表示找到第一个匹配后,只要还有文本没有尝试,那么,它将继续找出其它所有匹配结果. 在这个例子,找到两个匹配分别为mh(0)和mh(1). 其科室名即括号捕获的内容分别保存在这两个匹配的特殊变量$1中,VBA可以利用Match对象的submatches属性提取它们.(提示:如果不明白代码意思,请回到第一篇第二章查阅)











补充内容 (2016-6-6 19:28):
量词中还有一个 {n,} 表示出现n次及以上

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-6-11 15:57 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 liu-aguang 于 2014-6-17 19:18 编辑

  .正则元字符—-字符()位置表示法
  正则提供了一些表示位置元字符(序列),它可以锚定特定字符(),有时使用它们可以提高匹配效率.除了前面介绍的^$,还有:
捕获3.PNG
   
()单词分界符\b
  在英文环境中,匹配一个字边界,即字与空格间的位置。例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”
  它匹配这样一个位置:该位置一边是英文单词字符,另一边不是.也可以理解为该位置两边的字符,其中一个可以被\w匹配,另一个字符则可被\W匹配.所以在英文环境中,可匹配四种位置     (本文中英文单词字符指[a-zA-Z0-9_]):
   1) 在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)
   2) 在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)
   3) 在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后
   4) 在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面
  下面这个例子可让你明白单词分界符的用途:
  目标文本:He captured a catfish for his cat
  正则表达式1:
   cat
  正则表达式2:
   \bcat\b
    任务要求:用字符串fat,替换文本中的cat.
  代码:
sub test()
  dim s$
  with createobject("vbscript.regexp")
     .pattern="cat"      '分别用上面两个表达式测试
     .global=true
     s=.replace("He captured a catfish for his cat","fat")
  end with
  msgbox s
end sub
    你能分析结果差异的原因吗?
  
()非单词边界\B
   非字边界匹配。“er\B”匹配“verb”中的“er”,但不匹配“never”中的“er”
  它是\b取反.\B总是匹配两个同时被\w\W匹配的字符之间的位置.它匹配下列位置:
    1)在目标文本的第一个字符之前如果第一个字符不是单词字符;
    2)在目标文本的最后一个字符之后,如果最后一个字符不单词字符;
  3)在两个单词字符之间;
    4)在两个非单词符之间;
    5)空串
  在非英文环境中,没有单词边界;全部是非单词边界.所以应用范围很窄.

   ()肯定顺序环视与否定顺序环视
  以一个实例来讨论:
  1) (?=98)
  2) (?!98)
  第一个是肯定环视,表示子字符串”98”前面的位置;第二个是否定环视,表示不是子字符串”98”的位置.
  例:
  目标文本:”window97升级为window98”
  如果把它们作为正则表达式作用于该文本,则该文本中只有”98”前一个位置上才能被(?=98)匹配;除这个位置外,其它所有位置都可以被(?!98)匹配.它的工作原理是:
  在每个位置上查找该位置后是否跟着一个字符9,再然后再跟着一个字符8.如果是,(?=98)报告匹配成功,(?!98)报告匹配失败;反之,(?=98)报告失败,(?!98)报告成功.
  利用它们可以锚定特定字符串,:正则表达式
   Window(?=98)
  表示匹配后面跟着字符串”98”的字符串”window”.如果用它作用于上面目标文本,那么它只能匹配window98前面的”window”.
    而正则表达式:
    Window(?!=98)
  表示匹配后面没有跟着字符串”98”的字符串”window”.如果用它作用上面目标文本,那么它它只能匹配widow97前面的”window”
  环视只是简单地测试其中子表达式能否在当前位置匹配后面的文本.无论是什么样的结果,它都不会占有被测试的文本.:
  目标文本:”正则ABC”
  正则:(?!=\W+).{2}
  代码:
Sub test()
   Dim re,mh,s$
   S=”正则ABC”
  With createobject(“vbscript.regexp”)
       .pattern=”(?=\W+).{2}”
       Set mh=.Execute(s)
  End with
  For each k in mh
      Debug.print k                ' “正则
    next
End sub
  讨论:
  匹配结果是:”正则”.我们来分析一下匹配过程:
  在文本的开始位置,正则引擎首先尝试(?!=\W+),即检查该位置后面有无一个或一个以上的非英文单词字符.结果它找到"正则"二个字符是非英文字符,引擎报告第一个子表达式匹配成功;接着尝试第二个子表达式:”.{2}”,即匹配两个任意字符,这两个字符就是正则”.正则表达式中子表达式尝试完毕,最后报告成功而结束.
     我们看到(?!=\W+),并没有消耗正则字符串,如果消耗了,那么结果应该是”AB”.
  最后要指出一点的是:虽然环视表达式中有圆括号,但它是非捕获性的.并且圆括号与?、!或=是一个不可分割的整体.





补充内容 (2016-10-29 20:34):
更正: 正则中没有(?!=...), 本页中出现的(?!=...)是笔误, 应该为(?!...)

TA的精华主题

TA的得分主题

发表于 2014-6-11 16:10 | 显示全部楼层
liu-aguang 发表于 2014-6-11 14:41
(三)字符组缩略表示法
对于一些常用的字符类,正则提供了简略表示法:

(七)在哪里?

应该是【十六进制转义:\xnum (num是一个十六进制数)】吧。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-21 18:19 , Processed in 0.048070 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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