CottLi
3/4/2020 - 9:06 AM

VBA正则表达式

Option Explicit

'一 正则表达式

    ' 正则表达式是处理字符串的外部工具,它可以根据设置的字符串对比规则,用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。

'正则表达式的作用:
    '1、完成复杂的字符串判断
    '2、在字符串判断时,可以最大限度的避开循环,从而达到提高运行效率的目的。

'二 使用方法

'1、引用法
'点击VBE编辑器菜单:工具 - 引用,选取: Microsoft VBScript Regular Expressions 5.5,引用后在程序开始进行如下声明
Dim regex As New RegExp

'2、直接他建法:代码引用,后期绑定
Dim regex As Object     ' 声明对象
Set regex = CreateObject("VBScript.RegExp")     '创建正则对象

'三 常用属性
    '1 Global属性:
        '如果值为true,则搜索全部字符
        '如果值为False,则搜索到第 1 个即停止
'1 例:
    Dim reg As New RegExp
    Dim sr
    sr = "ABCEA"
    With reg
        .Global = True  ' 查找所有符合正则表达式要求的字符
        .Pattern = "A"  ' 查找字符串中的字符 A
        Debug.Print .Replace(sr, "")    ' 输出 BCE,所有的A都被替换为空字符
    End With

'2 IgnoreCase 属性:是否忽略大小写,默认区分大小写(False)

'3 Pattern 属性:一个字符串,用来定义正则表达式。缺省值为空文本。

'4 Multiline 属性,如果字符串使用了多行(换行符), 则该参数为 True 时,字符串的每一行行尾都是结尾。
'  于是,使用 $ 判断结尾时,每一行作为结尾;该参数设为 False 时,只有这个字符串最后的行为才是结尾;

    Dim reg As New RegExp
    Dim sr
    sr = "AEA" & Chr(10) & "ABCA"   ' 换行符 Chr(10) 的存在使得 sr 为两行的字符串
    With reg
        .Global = True              ' 在 sr 中查找所有满足正则表达式要求的字符串
        .MultiLine = True           ' 多行字符串的每一行结尾均为行尾
        '.Pattern = "A$"
        .Pattern = "^A"
        Debug.Print .Replace(sr, "")
    End With

'5  Execute 方法:返回一个集合对象
    '返回一个 MatchCollection 对象,该对象包含每个成功匹配的 Match 对象,
    '返回的信息包括:
        'FirstIndex:开始位置
        'Length; 长度
        'Value:长度

    Dim reg As New RegExp
    Dim sr, mat
    sr = "A454BCEA5"
    With reg
        .Global = True
        .Pattern = "A\d+"           ' 规则为:A后面有任意多个字符,则 A454BCEA5 和 A5 都符合
        Set mat = .Execute(sr)      ' 将字符串 sr 中所有成功匹配的字符串片段(Match对象)放入对象集合 mat 中
    End With

    ' 提取字符串中的数字并进行求和
    Function ns(rg)
        Dim reg As New RegExp
        Dim sr, mat, s, m, x
        With reg
            .Global = True
            .Pattern = "\d*\.?\d*"      ' . 是特殊符号, \. 表示点号;\.? 表示小数点出现0次(整数)或1次(小数);
                                        ' \.? 前后的 \d* 表示小数点前后的数字为任意多个;
            Set mat = .Execute(rg)
            For Each m In ma    ' 遍历 Match对象集合 中的每个 Match 对象
                s = s + Val(m)  ' 获取字符串片段并将字符串转换为数值(Val)
            Next m
        End With
        ns = s
    End Function

'6、Text方法:返回一个布尔值,判断两个字符串是否匹配成功
    Dim reg As New RegExp
    Dim sr
    sr = "BCR6EA"
    With reg
        .Global = True
        .Pattern = "\d+"    ' 规则:是否包含数字
        If .test(sr) Then MsgBox "字符串中含有数字"
    End With
        
 
Function 提取中文(rg As String, k As Integer)
    Dim regx As New RegExp      ' 引用法创建对象
    With regx
        .Global = True          ' 匹配字符串中所有匹配的地方
        If k = 1 Then           ' k = 1 表示提取数字
            .Pattern = "\D"     ' 匹配字符串中的非数字
        ElseIf k = 2 Then       ' k = 2 表示提取出中文
            .Pattern = "\w"     ' 匹配字符串中的 字母、数字或下划线
        End If
        提取中文 = .Replace(rg, "") ' 将非数字(k=1时)或非中文(k=2时)删除(替换为空字符串)
    End With
End Function
Option Explicit

'正则表达式的核心是设置对比的规则,也就是设置Pattern属性,而组成这些规则除了字符本身以外,是具有特定含义的符号。
'下面介绍的是正规表达式中常用符号的第一部分。

' \ 号
    '1.放在不便书写的字符前面,如换行符(\r),回车符(\n),制表符(\t),\自身(\\)
    '2.放在有特殊意义字符的前面,表示它自身,"\$","\^","\."
    '3.放在可以匹配多个字符的前面
    
    '\d 0~9的数字
    '\w 任意一个字母或数字或下划线,也就是 A~Z,a~z,0~9,_ 中任意一个
    '\s 包括空格、制表符、换页符等空白字符的其中任意一个
    
    ' *** 以上改为大写时,为相反的意思,如\D 表示非数字类型 ***
    
    Dim regx As New RegExp
    Dim sr
    sr = "AE45B646C"
    With regx
        .Global = True
        .Pattern = "\D" '排除非数字
        Debug.Print .Replace(sr, "")   ' 按照规则(Pattern设置的“非数字”)替换:把所有非数字的字符替换为空字符,即筛选出字符串中的数字
    End With

'.(点) : 匹配除换行符以外的所有字符,起着占位的作用(占位符)


'+ 号: 表示 + 号前面的一个(或一类)字符可以有任意多个重复的,至少出现一次
    Dim regx As New RegExp
    Dim sr
    sr = "A234CA7A"
    With regx
        .Global = True
        .Pattern = "A\d+"   ' 表示A后面至少接着 1 个数字,则A234 和 A7 均满足
        Debug.Print .Replace(sr, "")  ' A234 C A7 A 中的A234和A7都被替换为空字符,只剩下 CA
    End With
    
'{}号:设置字符(同一类)重复次数
    '1 {n} 重复n次
        Dim regx As New RegExp
        Dim sr
        sr = "A234CA7A67"
        With regx
            .Global = True
            .Pattern = "\d{2}" '连续两个数字,则 23 和 67 满足条件
            Debug.Print .Replace(sr, "")    ' 输出的结果为 A4CA7A
        End With
        
    '2  {m,n}最小重复m次,最多重复n次
        Dim regx As New RegExp
        Dim sr
        sr = "A234CA7A6789"
        With regx
            .Global = True
            .Pattern = "\d{2,3}" '连续两个数字或连续三个数字,则 234 和 67 满足条件
            Debug.Print .Replace(sr, "")        ' 输出的结果为 ACA7A
        End With

    '3 {m,} 最少重复m次;当 m = 1 时相当于 + 号
        Dim regx As New RegExp
        Dim sr
        sr = "A2348t6CA7A67"
        With regx
            .Global = True
            .Pattern = "\d{2,}" '连续两个数字或连续两个以上的数字,则 2348 和 67 都满足
            Debug.Print .Replace(sr, "")
        End With
        
'* 可以出现任意次(可以为 0 次)  相当于 {0,},比如:"\^*b"可以匹配 "b","^^^b"...

' ?
    '1 匹配表达式0次或者1次,相当于 {0,1},比如:"a[cd]?"可以匹配 "a","ac","ad";
    '  ? 最大的作用是判断小数点:"\d+\.?\d+"
        Dim regx As New RegExp
        Dim sr
        sr = "A23.48CA7A6..7"
        With regx
            .Global = True
            .Pattern = "\d+\.?\d+" ' . 是特殊符号, \. 表示点号;\.? 表示小数点出现0次(整数)或1次(小数);
                                    ' \.? 前后的 \d+ 表示小数点前后的数字至少为 1 个;
            Debug.Print .Replace(sr, "")
        End With

    '2 利用 +? (或 *? )的格式可以分段匹配
        Dim regex As New RegExp
        Dim sr, mat, m
        sr = "<td><p>aa</p></td> <td><p>bb</p></td>"    ' HTML预言的字符串
        With regex
            .Global = True
            .Pattern = "<td>.*?</td>"   ' . 表示任意字符, .* 表示任意多个任意字符, .*? 加上
            Set mat = .Execute(sr)      ' 把多段符合正则条件的字符串片段装到 mat 集合对象中
            For Each m In mat           ' 遍历对象集合中的每个对象
                Debug.Print m           ' 输出字符串片段
            Next m
        End With
    
        ' +? 的示例:
        sr = " aba  aca  ada "
        With regex
            .Global = True
            .Pattern = "\s.+?\s"        ' \s 空格、制表符等空白字符,
            Set mat = .Execute(sr)      ' 把多段符合正则条件的字符串片段装到 mat 集合对象中
            For Each m In mat           ' 遍历对象集合中的每个对象
                Debug.Print m           ' 输出字符串片段
            Next m
        End With

' ******* 注意 ********
' * 和 + 限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。比如:
str = "<h1>RUNOOB-菜鸟教程</h1>"
regx.Pattern = "<.*>"     ' 贪婪匹配:从开始小于符号 (<) 到关闭 h1 标记(</h1>)的大于符号 (>) 之间的所有内容:<h1>RUNOOB-菜鸟教程</h1>
regx.Pattern = "<.*?>"      ' *? 非贪婪匹配:匹配最近的一个大于号 (>) ,匹配结果:<h1>
'[]
'使用方括号 [ ] 包含字符集合,能够匹配其中任意一个字符。用 [^ ] 不包含一系列字符,
'则能够匹配其中字符之外的任意一个字符。同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个

'1 能匹配方括号中字符集的一个即可,注意不是组合匹配
    Dim regx As New RegExp
    Dim str
    str = "ABDC"
    With regx
        .Global = True
        .Pattern = "[BC]"   ' 匹配 str 中的字符B或字符C
        Debug.Print .Replace(str, "")       ' 替换匹配的字符得到结果
    End With

'2 非括号内的字符
    regx.Pattern = "[^BC]"  ' 匹配字符串中不是B或C的其他任何字符

'3 在一个区间
    regx.Pattern = "[a-h]"      ' 字母区间,等价于 [abcdefgh]
    regx.Pattern = "[1-47-9]"   ' 数字区间,等价于 [1234789]
 

Option Explicit

'^符号:匹配输入字符串开始的位置,限制其后的字符在字符串最前面,如^\d表示以数字开头
    regx.Pattern = "^\d*"   ' 字符串以数字开头

'$符号:匹配输入字符串结尾的位置,限制其前面的字符在最后面,如 A$ 表示最后一个字符是A
    str = "R243r"
    regx.Pattern = "^\D.*\D$"   ' 字符串以非数字开头并以非数字结尾

'\b :表示空格以及字符串的开头和结尾
    str = "A12dA56 A4"
    regx.Pattern = "\bA\d+"     ' 表示字符A左边有一个空格,或者A在字符串的最左边,A后接数字串(至少一个数字)。
                                ' 移除掉所有匹配的字符串片段后原字符串为 dA56

    str = "ad bf cr de ee"
    regx.Pattern = ".+?\b"
'| :设置或关系的多个条件,匹配多个条件中的一个即可
    str = "A12DA56 A4B34D"
    regx.Pattern = "A\d+|B\d+"          ' 移除掉所有匹配的字符串片段后原字符串为:D D
        
'\un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。主要用于区分汉字!!
    str = "A12d我A爱56你 A4"
    regx.Pattern = "[\u4e00-\u9fa5]"    ' 汉字的Unicode编码介于 4e00 ~ 9fa5 之间。
                                        ' 移除掉所有匹配的字符串片段后原字符串为 A12dA56 A4