正则表达式是对字符串中的字符类别、组合规则进行描述,以进行匹配(返回一个匹配集合)或搜索。正则表达式在字符串(文本)的处理方法功能强大,一般的程序语言都有正则表达式功能,其用法(语法)也大同小异。

正则表达式能处理某一类具有某些相似特征的字符或字符串(一般程序语言的字符串处理函数处理的是具体字符串的字面量)。

正则表达式是强大、便捷、高效的文本处理工具。利用它使用者可以描述和分析任何复杂的文本,配合编程语言或文本编辑器提供的支持,正则表达式能够查找、替换、提取、验证、添加、删除、分离和修整各种类型的文本和数据。

本头条号前两天的一篇文章有提到用正则表达式如果分离出一个单元格内的中文、英文、数字文本,这正是正则表达式的优势所在。如:

^[ -]?\d (\.\d )?$|^\.\d $ 匹配任意可选符号的实数;

[\u4e00-\u9fa5] 匹配所有单个中文字符;

[a-zA-Z] 匹配所有单个英文字符

1 创建正则表达式对象

1.1 前期绑定:在VBA代码编辑器中的"Tools"菜单中,选中"References...",然后引用Microsoft VBScript Regular Expressions 5.5类库,然后直接定义对象:Dim reg As New RegExp。

1.2 后期绑定:使用CreateObject方法定义对象:CreateObject("VBSCRIPT.REGEXP")。

前一种方式的优点是可以有编辑器的Intellisense支持。

2 RegExp对象的属性

Global - 设置或返回一个 Boolean 值,该值指明在整个搜索字符串时模式是全部匹配还是只匹配第一个。如果搜索应用于整个字符串,Global 属性的值应该为 True,否则其值为 False。默认的设置为True。

Multiline - 返回正则表达式是否具有标志m, 缺省值为False。如果指定的搜索字符串分布在多行,这个属性是要设置为True的。

IgnoreCase - 设置或返回一个Boolean值,指明模式搜索是否区分大小写。如果搜索是区分大小写的,则 IgnoreCase 属性应该为False;否则应该设为True。缺省值为True。

Pattern - 设置或返回被搜索的正则表达式模式。 被搜索的正则字符串表达式。它包含各种正则表达式字符。

3 RegExp对象的方法

Execute - 对指定的字符串执行正则表达式搜索。需要传入要在其上执行正则表达式的文本字符串。正则表达式搜索的设计模式是通过 RegExp对象的Pattern来设置的。Execute方法返回一个 MatchCollection 对象(Matches集合),其中包含了在string中找到的每一个匹配的Match对象。如果未找到匹配,Execute将返回空的 MatchCollection 对象。

Replace - 替换正则表达式匹配到的文本。

Test - 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。RegExp.Global属性对Test方法没有影响。如果找到了匹配的模式,Test方法返回True;否则返回False。

4 MatchCollection对象与Match对象

匹配到的所有对象放在MatchCollection集合中,这个集合对象只有两个只读属性:

Count:匹配到的对象的数目

Item:集合的又一通用方法,需要传入Index值获取指定的元素。

一般,可以使用For Each语句枚举集合中的对象。集合中对象的类型是Match。

Match对象有以下几个只读的属性:

FirstIndex - 匹配字符串在整个字符串中的位置,值从0开始。

Length - 匹配字符串的长度。

Value - 匹配的字符串。

SubMatches - 集合,匹配字符串中每个分组(正则表达式中使用()进行分组)的值。作为集合类型,有Count和Item两个属性。

excelvba正则表达式用法(利用正则表达式处理字符串)(1)

5 正则表达式的分类及常用符号

Excel中正则表达式概括分为3类:

第一类是字符类,例如\d可以任意匹配一个数字字符,可以匹配0-9,[a-z]可以匹配任意一个小写字母;

第二类是限定符,可以控制字符出现的个数,例如手机号码一般是11位的数字,我们就可以使用[1-9]\d{11}来表示,因为手机号码第一位不能为0,所以用[1-9]来匹配1-9中任意一个数字;

第三类是定位符,控制字符出现的位置,如\\b就是表示单词分界符。

此外,若想用好正则表达式,首先下面的几个常用字符必须要掌握:

excelvba正则表达式用法(利用正则表达式处理字符串)(2)

通过上面各种符号的灵活组合就可以去匹配任何你想要的规则,搜索到你想要的文本信息。

5.1 常用符号

[0-9]表示匹配任意一个数字

[a-zA-Z]表示匹配任意一个英文字母

[\u4e00-\u9fa5]表示匹配任意一个中文字符

. 匹配除换行符以外的任意字符

w 匹配字母或数字或下划线或汉字

s 匹配任意的空白符

d 匹配数字

^ 匹配字符串的开始位置,如"^d ",匹配以数字开头的字符。该字符还可以用在[]中,如[^0-9]表示配置不是数字的字符。

$ 匹配字符串的结束

* 重复零次或更多次

重复一次或更多次

? 重复零次或一次

{n} 重复n次

{n,} 重复n次或更多次

{n,m} 重复n到m次

W 匹配任意不是字母,数字,下划线,汉字的字符

S 匹配任意不是空白符的字符

D 匹配任意非数字的字符

B 匹配不是单词开头或结束的位置

[^x] 匹配除了x以外的任意字符

[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

[ab5@] 匹配 "a" 或 "b" 或 "5" 或 "@"

[^abc] 匹配 "a","b","c" 之外的任意一个字符

[f-k] 匹配 "f"~"k" 之间的任意一个字母

[^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符

| 左右两边表达式之间 "或" 关系,匹配左边或者右边

( ) 有下面两种情况:

I 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰

II 取匹配结果的时候,括号中的表达式匹配到的内容可以通过特殊变量$1,$2……或\\1,\\2……被单独得到。正则表达式对象的Execute方法会返回一个匹配到的字符串的集合对象,其中的Submatches属性是一个集合属性,集合中元素个数与正则表达式中使用的捕获性括号的个数相同,每个元素的值就是括号包围起来的内容。

5.2 控制字符表示法:\cChar

在ASCII码表中,十进制代码为1-26的字符全是控制字符,可以用”\c”连接字母A-Z之一来表示。 即\cA-\cZ分别表示代码为1-26的控制字符。如”\cM”,表示回车符。

5.3 ASCII码表中字符的八进制转义表示法:\num

VBscript正则可用字符的八进制编码转义来表示ASCII字符:它的序列由反斜线和字符的八进制编码组成。

八进制转义法表示字符范围:\0--\377,包括ASCII码表和扩展表中的256个字符。该表示法主要用于难以输入的字符。如\12表示换行;\101表示A。

5.4 ASCII码表中字符的十六进制转义表示法: \xnum

一个小写的\x后跟两个十六进制数字可以匹配ASCII字符集中的一个字符

可匹配范围\x00--\xFF,但一般用\x00--\x7F表示ASCII字符集中的前128个字符。\x80-\xFF(ASCII扩展码表字符),一般用Unicode代码点表示法替代。如\x20表示空格。

5.5 Unicode码表中字符的十六进制转义表示法:\unum

Unicode码一般用称之为代码点来表示一个字符。它是一个十六进制数。

正则表达式中,用“\u”序列后面紧跟字符unicode代码点(十六进制数)表示该字符。

如[\u4e00-\u9fff]表示所有汉字。

I \unum表示法可表示代码点在U 0000--U FFFF范围内的unicode字符。Unicode本身在发展中,已经出现超过4位的代码点,VBscript正则是不支持,但它们是很难遇到的字符。

II 用字符组[ ]表示Unicode字符范围时,也可直接用表中起点字面字符与终点字面字符表示。比如大陆中文字符在Unicode表中,起始代码点是U 4e00,是表示中文字符”一”,终点代码点U 9fff,该代码点未定义,而”龥”字在终点附近,所以我们也可以用”[一-龥]”表示所有中文字之一。顺便提示一点,汉字在Unicode中的分布,基本无规律。不要想像"一",后面就是"二"等等。

III 有些流派的正则可以用Unicode的属性来方便表示不同类别的汉字或其它语言文字,但VBscript 5。5是不支持的。

5.6 肯定顺序环视与否定顺序环视

目标文本:”window97升级为window98”

要匹配字符98前一个位置,使用正由表达式:(?=98)

除这个位置外,其它所有位置都可以被(?!98)匹配。

如:

Sub test()

Dim re, mh, s$

s = "window97升级为window98"

With CreateObject("vbscript.regexp")

.Pattern = "window(?=98)"

Set mh = .Execute(s)

s2 = .Replace(s, "")

End With

For Each k In mh

Debug.Print k

Next

Debug.Print s2

End Sub

立即窗口显示:

window

window97升级为98

6 抑制量词的贪婪性:?

前面已经知道,所有量词都是贪婪的,或称之为匹配优先的。他们总是匹配尽可能多的字符。下面例子可以了解什么是贪婪:

目标文本:“This is a <EM>first</EM> test”

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 >结果呢?这就是贪婪匹配;

如果想匹配提取标签<EM>或</EM>呢?也就是想要非贪婪匹配呢?

为了解决这类问题,正则引入了一个元字符”?”,将它紧跟在量词之后,如”。*?”,则可抑制量词的贪婪性。让它变成忽略优先量词。忽略优先量词总是匹配尽可少的字符:

正则表达式修改为下式即可:

<.*?>

7 返回匹配到的字符串

7.1 全部返回

正则表达式匹配到的字符串放在MatchCollection集合,可遍历其元素获得全部返回。

7.2 分组返回

可以在正则表达式中使用()进行分组, 取匹配结果的时候,括号中的表达式匹配到的内容可以通过特殊变量$1,$2……或\1,\2……被单独得到。或者通过MatchCollection集合中的子集合SubMatches的Item属性获得。

(集合中的元素可以通过for each遍历得到,也可以通过下标(i)获得。)

如下面实例:在匹配到的数字后添加重量单位KG:

Sub testrep()

Dim reg, s$

s = "他们体重分别是:张三56,李四49,王五60。"

Set reg = CreateObject("vbscript.regexp")

reg.Pattern = "(\d )"

reg.Global = True

s = reg.Replace(s, "$1KG")

MsgBox s

End Sub

8 匹配实数正则表达式的解释

[ -]?\d (\.\d )?|\.\d

或-可用字符组[ -],它们可有可无可用[ -]?

整数部分部分可用\d

小数部分可用\.\d ,小数部分可有可无,可用可选项元字符?,由于小数部分如果出现则小数点与后面的数据将同时出现,反之,同时不出现,所以用分组括号包围让?号整体作用即:(?:\.\d )?

于是整合起来就是[ -]?\d (?:\.\d )?

整数部分也不是必须出现的,即实际浮点数表示法,可以存在只是小数部分也合法。能否用[ -]?\d*\(\.\d )?表示各种情形呢?这是不行的,因为在这个表达式中所有子表达式都可以不出现,就意味着什么都不匹配也匹配成功,也意味着什么都可以匹配。

它的解决办法是用选择符把它们作为两部分分别匹配两种可能的情况,即

[ -]?\d (\.\d )?|\.\d

9 简单正则表达式应用实例:

excelvba正则表达式用法(利用正则表达式处理字符串)(3)

上例如果是与工作表的单元格数据交互,字符串S的值可以来自于单元格字符串,如S = Range("A1").

这个简单的例子说明了正则表达式实现的一般步骤:

1、创建变量:这个例子中,变量regx是一个对象,S是字符串变量,Strnew也是字符串变量;

2、把目标文本赋值给变量S,一般来源于单元格;

3、创建一个正则对象regx;

4、设置正则对象regx的pattern属性,即把正则表达式以字符串形式赋值给pattern;

5、设置正则regx对象的其它属性,例子中设置Global属性为真;

6、应用对象提供的方法,实现相应功能。例子中,利用regx对象的Replace方法实现替换;

7、输出处理后的字符串,一般赋值给单元格;

分离文本的实例:

excelvba正则表达式用法(利用正则表达式处理字符串)(4)

包含数值的文本利用正则表达式对文本求和的实例:

Function SumValueInText(TargetRange As Range) As Double

Dim mRegExp As Object '正则表达式对象

Dim mMatches As Object '匹配字符串集合对象

Dim mMatch As Object '匹配字符串

Set mRegExp = CreateObject("Vbscript.Regexp")

With mRegExp

.Global = True 'True表示匹配所有, False表示仅匹配第一个符合项

.IgnoreCase = True 'True表示不区分大小写, False表示区分大小写

.Pattern = "([0-9])?[.]([0-9]) |([0-9]) " '匹配字符模式

Set mMatches = .Execute(TargetRange.Text) '执行正则查找,返回所有匹配结果的集合,若未找到,则为空

For Each mMatch In mMatches

SumValueInText = SumValueInText CDbl(mMatch.Value)

Next

End With

Set mRegExp = Nothing

Set mMatches = Nothing

End Function

在VBA中有like操作符,可以按正则表达式匹配单个字符,如:

以下表达式中s表示一个字符串:

flag = s Like "[a-z,A-Z]"

flag = s Like "#"

flag = s like "([0-9] .[0-9] )|[0-9]|(-[0-9])"

flag = s like "[一-龥]"

flag = s like "[a-zA-Z]"

flag = s like "[^a-zA-Z0-9\u4e00-\u9fff\ ]"

上面表达式中的flag是一个逻辑值。

-End-

,