【转】VBScript-RegExp对象的详细用法
引自小白的博客
RegExp对象是VBScript中用于提供简单的正则表达式支持的对象。VBScript中所有和正则表达式有关的属性和方法都与这个对象有关联。
Dim re
Set re = New RegExp
这个对象有三个属性和三个方法,如表9-1所示。
表9-1
属 性 |
Global属性 |
IgnoreCase属性 |
|
Pattern属性 |
|
方 法 |
Execute方法 |
Replace方法 |
|
Test方法 |
接下来的几节会深入地介绍这些属性和方法。此外还会介绍您将在模式中用到的正则表达式符号。
1 Global属性
Global属性负责设置或返回一个Boolean值,指明模式是匹配整个字符串中所有与之相符的地方还是只匹配第一次出现的地方(参见表9-2)。
表9-2
代码 |
object.Global [= value ] |
对象 |
RegExp对象 |
值 |
有两个可能的值:True和False |
如果Global属性的值是True,那就会对整个字符串进行查找;否则就不会。默认值是False—— 并不是微软的某些文档中说的True |
下面的例子利用Global属性确保所有的"in"都会被修改。
Dim re, s
Set re = New RegExp
re.Pattern = "/bin"
re.Global = True
s = "The rain in Spain falls mainly on the plains."
MsgBox re.Replace(s, "in the country of")
2 IgnoreCase属性
IgnoreCase属性负责设置或返回一个Boolean值,指明模式匹配是否大小写敏感(参见表9-3)。
表9-3
代码 |
object.IgnoreCase [= value ] |
对象 |
RegExp对象 |
值 |
有两个可能的值:True和False |
如果IgnoreCase属性的值为False,搜索为大小写敏感;如果是True,则不是。默认是False—— 并不是微软的某些文档中说的True |
继续看这个例子,之前看过了Global属性;如果要匹配的字符串中有“In”,就必须告诉VBScript在进行匹配时要忽略大小写。
Dim re, s
Set re = New RegExp
re.Pattern = "/bin"
re.Global = True
re.IgnoreCase = True
s = "The rain In Spain falls mainly on the plains."
MsgBox re.Replace(s, "in the country of")
3 Pattern属性
Pattern属性设置或返回用于搜索的正则表达式(参见表9-4)。
前面所有的例子都用到了Pattern。
Dim re, s
Set re = New RegExp
re.Pattern = "/bin"
re.Global = True
s = "The rain In Spain falls mainly on the plains."
MsgBox re.Replace(s, "in the country of")
表9-4
代码 |
object.Pattern [= "searchstring"] |
对象 |
RegExp对象 |
搜索字符串 |
需要搜索的正则字符串表达式。可能含有一些正则表达式字符—— 可选的 |
4 正则表达式字符
正则表达式的强大并不是来自于用字符串做模式,而是在模式中使用特殊字符。表9-5列出了所有的这些字符,以及每个字符在代码中的作用。
大写特殊字符的作用与相应的小写特殊字符的作用相反。
表9-5
字 符 |
描 述 |
/ |
表示下一个字符是特殊字符或文字常量 |
^ |
匹配输入的开头 |
$ |
匹配输入的结尾 |
* |
匹配前一个字符零次或多次 |
+ |
匹配前一个字符一次或多次 |
? |
匹配前一个字符零次或一次 |
. |
匹配除换行符以外的任何单个字符 |
(pattern) |
匹配并记住这个模式。可以用[0]…[n]从结果的matches集合中获取匹配到的字符串。要匹配括号本身,在前面加上斜杠—— 用"/("或"/)" |
(?:pattern) |
匹配但不捕获模式,也就是不会存储匹配结果供以后使用。这可以用于使用"or"字符(|)合并模式的不同部分。例如,"anomal(?:y|ies)"比"anomaly|anomalies"要划算得多 |
(?=pattern) |
当所要搜索的字符串匹配了模式的开头部分时就接着匹配这一部分。这是一个非捕获匹配,也就是说不会保存匹配结果供以后使用。例如,"Windows (?=95|98|NT|2000|XP|Vista)"能匹配"Windows Vista"中的Windows而不能匹配"Windows 3.1"中的Windows |
(?!pattern) |
与上一个相反,这会匹配模式中没有出现的内容。这是一个非捕获匹配,也就是说不会保存匹配结果供以后使用。例如,"Windows (?=95|98|NT|2000|XP|Vista)"能匹配"Windows 3.1"中的Windows而不能匹配"Windows Vista"中的Windows |
x|y |
匹配x或y |
(续表)
字 符 |
描 述 |
{n} |
准确地匹配n次(n必须是一个非负整数) |
{n,} |
至少匹配n次(n必须是一个非负整数—— 注意结尾的逗号) |
{n,m} |
至少匹配n次,最多匹配m次(m和n必须都是非负整数) |
[xyz] |
匹配其中包括的任一个字符(xyz表示一个字符集) |
[^xyz] |
匹配其中不包括的字符(^xyz表示一个字符集的补集) |
[a-z] |
匹配指定范围内的字符(a-z表示字符的范围) |
[m-z] |
匹配指定范围以外的字符(^m-z表示指定范围的补集) |
/b |
匹配一个单词边界,这个位置在单词和空格之间 |
/B |
匹配一个非单词边界 |
/d |
匹配数字。等价于[0-9] |
/D |
匹配非数字。等价于[^0-9] |
/f |
匹配换页符 |
/n |
匹配换行符 |
/r |
匹配回车符 |
/s |
匹配空白,包括空格、制表符、换页符等。等价于"[/f /n /r /t /v ]" |
/S |
匹配非空白的字符。等价于"[^/f /n /r /t /v ]" |
/t |
匹配制表符 |
/v |
匹配纵向制表符 |
/w |
匹配字母、数字,以及下划线。等价于"[A-Za-z0-9_]" |
/W |
匹配非字符数字。等价于"[^A-Za-z0-9/_]" |
/. |
匹配. |
/| |
匹配| |
/{ |
匹配{ |
/} |
匹配} |
// |
匹配/ |
/[ |
匹配[ |
/] |
匹配] |
/( |
匹配( |
/) |
匹配) |
$ num |
匹配num,其中num是正整数。返回匹配结果的引用 |
/n |
匹配n,其中n是八进制转义符。八进制转义符的长度应为1、2或3 |
/uxxxx |
匹配UNICODE形式的ASCII字符 |
/xn |
匹配n,其中n是十六进制转义符。十六进制转义符必须是两位长度 |
这其中很多代码都无需太多的说明,但是有些例子可能需要别人的帮助才能理解。
匹配一类字符
您已经见过一个简单的模式:
re.Pattern = "in"
它通常用来匹配一类字符。通过将需要匹配的字符放在方括号中就能实现。例如,下面这个例子将单个数字换成更通用的术语。
Dim re, s
Set re = New RegExp
re.Pattern = "[23456789]"
s = "Spain received 3 millimeters of rain last week."
MsgBox re.Replace(s, "many")
这段代码的输出如图9-11所示。
图9-11
在这个例子中,数字“3”被替换成了文本“many”。正如您所期望的,可以指定一个范围来缩短这个模式。这个模式跟前一个的功能完全一样。
Dim re, s
Set re = New RegExp
re.Pattern = "[2-9]"
s = "Spain received 3 millimeters of rain last week."
MsgBox re.Replace(s, "many")
替换数字和非数字
经常需要替换数字。实际上,由于经常要用到模式[0-9](包括所有数字),所以有一种[0-9]的等价快捷方式:/d。
Dim re, s
Set re = New RegExp
re.Pattern = "/d"
s = "a b c d e f 1 g 2 h ... 10 z"
MsgBox re.Replace(s, "a number")
替换后的字符串如图9-12所示。
图9-12
如果要匹配非数字的字符怎么办?在方括号中使用^符号。
在方括号外使用^的意义就完全不同了,稍后会对此做讨论。
这样就可以使用下面的模式匹配非数字的字符:
re.Pattern = "[^,0-9]" 'the hard way
re.Pattern = "[^/d]" 'a little shorter
re.Pattern = "[/D]" 'another of those special characters
最后一个模式使用了另一种特殊字符。在大部分情况下这种特殊字符只是减少了您的输入次数(或是一种有效的记忆方法),但在有些情况下,比如遇到匹配制表符和其他不能打印的字符时,这就很有用了。
锚定和缩短模式
有三种特殊字符用于锚定模式。它们本身不匹配任何字符,但是可以要求另一个模式必须出现在输入的开头(在[]外使用^)、输入的结尾($)或是单词边界(您已经见过的/b)。
另一种缩短模式的方法是使用重复数。基本的思路就是在模式后面指定重复的次数。例如,下面这个模式,如图9-13所示,可以匹配多个数字并替换它们。
Dim re, s
Set re = New RegExp
re.Pattern = "/d{3}"
s = "Spain received 100 millimeters of rain in the last 2 weeks."
MsgBox re.Replace(s, "a whopping number of")
图9-13
如果不在代码中使用重复数,如图9-14所示,它会留下最后字符串中的"00"。
图 9-14
Dim re, s
Set re = New RegExp
re.Pattern = "/d"
s = "Spain received 100 millimeters of rain in the last 2 weeks./"
MsgBox re.Replace(s, "a whopping number of")
还要注意,这里不能使用re.Global = True,因为这样会在结果中产生4个“a whopping number of”。结果如图9-15所示。
图 9-15
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "/d"
s = "Spain received 100 millimeters of rain in the last 2 weeks."
MsgBox re.Replace(s, "a whopping number of")
指定匹配的范围或最小次数
前面的表中已经罗列了,还可以指定匹配的最小次数{min}或范围{min, max,}。其中一些常用的重复模式也有专门的快捷方式。
re.Pattern = "/d+" 'one or more digits, /d{1, }
re.Pattern = "/d*" 'zero or more digits, /d{0, }
re.Pattern = "/d?" 'optional: zero or one, /d{0,1}
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "/d+"
s = "Spain received 100 millimeters of rain in the last 2 weeks."
MsgBox re.Replace(s, "a number")
这段代码的输出如图9-16所示。注意字符串“100”被替换了。
图 9-16
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "/d*"
s = "Spain received 100 millimeters of rain in the last 2 weeks."
MsgBox re.Replace(s, "a number")
上面这段代码的输出如图9-17所示。这里在每两个非数字的字符间插入了这个字符串,而数字则被替换了。
图9-17
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "/d?"
s = "Spain received 100 millimeters of rain in the last 2 weeks."
MsgBox re.Replace(s, "a number")
上面这段代码的输出如图9-18所示。这里也在每两个非数字的字符间插入了“a number”,而数字则被替换了。
图 9-18
记住匹配结果
最后一个要讨论的特殊字符是记住匹配的结果。如果要在用于替换的文本中使用部分或全部的匹配结果,这就很有用—— 详见Replace方法,其中一个例子使用了记住匹配的结果。
为了验证这一点,也为了将所有关于特殊字符的讨论集中在一起,我们来做点有实际意义的事情。搜索一个字符串,查找其中的URL。为了控制这个例子的复杂度和规模,这里只查找其中的"http:"协议,但是您还可以处理各种DNS域名,包括无限的域名层次。不要担心如何与DNS交流,只需要知道在浏览器中输入URL就足够了。
下一节中关于另一个RegExp对象方法的代码中会有更多的细节信息。现在,只需要知道Execute会执行模式匹配并通过集合返回各个匹配结果。这里是代码:
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "http://(/w+[/w-]*/w+/.)*/w+"
s = "http://www.kingsley-hughes.com is a valid web address. And so is "
s = s & vbCrLf & "http://www.wrox.com. And "
s = s & vbCrLf & "http://www.pc.ibm.com - even with 4 levels."
Set colMatches = re.Execute(s)
For Each match In colMatches
MsgBox "Found valid URL: " & match.Value
Next
如您所愿,其中主要的工作就是设置模式的那一行代码。看上去有点让人生畏,但实际上很容易理解。让我们将其分解开来:
1. 模式以固定的字符串http://开头。然后用圆括号将模式的主要部分括起来。下面高亮的模式会匹配一级DNS,包括尾部的点:
re.Pattern = "http://(/ w[ / w-]* / w / . )*/w+"
这个模式以一个您之前见过的特殊字符/w开头,用来匹配[a-zA-Z0-9],也就是英语中的所有数字和字母。
2. 用括号匹配字母数字或横杠,因为DNS中可以有横杠。为什么不使用与前面一样的模式?很简单,因为有效的DNS不能以横杠开始或结尾。然后用*重复匹配0个或多个字符。
re.Pattern = "http://(/w [ / w-]* /w/..*/w+"
3. 然后又严格地用字母数字,这样域名就不会以横杠结束。括号中的最后一个模式匹配用于分割DNS层次的点(.)。
不能单独使用点,因为那是一个特殊字符,正常情况下能匹配除换行符以外的任何字符。可以用反斜杠转义这个字符。
4. 在将这些东西封装到括号中之后,只需要继续使用*重复这个模式即可。所以下面高亮显示的模式可以匹配所有有效的域名以及其后的点。换句话说就是能匹配整个DNS中的一级域名。
re.Pattern = "http:// ( / w[ / w-]*/w/ .)*/w+"
5. 模式最后是顶级域名(比如com、org、edu等)所需的一个或多个字符。
re.Pattern = "http://(/w[/w-]*/w/.)*/ w+ "
9.2.5 Execute方法
这个方法将正则表达式应用到字符串上并返回Matches集合。这是代码中使用模式匹配字符串的启动开关,使用方法参见表9-6。
表9-6
代码 |
object.Execute( string ) |
对象 |
只能是RegExp对象 |
字符串 |
需要搜索的字符串—— 必需的 |
正则表达式搜索的模式就是RegExp对象的Pattern属性。
Dim re, s
Set re = New RegExp
re.Global = True
re.Pattern = "http://(/w+[/w-]*/w+/.)*/w+"
s = "http://www.kingsley-hughes.com is a valid web address. And so is "
s = s & vbCrLf & "http://www.wrox.com. And " s = s & vbCrLf &
"http://www.pc.ibm.com - even with 4 levels."
Set colMatches = re.Execute(s)
For Each match In colMatches
MsgBox "Found valid URL: " & match.Value
Next
要注意,有些语言对正则表达式结果的处理方式不一样,其Execute返回的是判断模式是否找到的布尔值。这种差异导致您经常会看到从其他语言中转换过来的正则表达式在VBScript中无法使用。
有些微软的文档也含有这类错误,不过其中大部分都已经改正了。
记住Execute的结果是一个集合,甚至很有可能是一个空集合。可以用if re.Execute(s).count = 0或专门为这个目的设计的Test方法来测试它。
6 Replace方法
这个方法用于替换在正则表达式搜索中找到的文本,用法参见表9-7。
表9-7
代码 |
object.Replace(string1, string2) |
对象 |
只能是RegExp对象 |
字符串1 |
这是发生替换的文本字符串—— 必需的 |
字符串2 |
这是用于替换的文本字符串—— 必需的 |
Replace方法返回一份RegExp.Pattern被string2替换后的string1的副本。如果字符串中没有发生匹配,那么就会返回没有任何改变的string1。
Dim re, s
Set re = New RegExp
re.Pattern = "http://(/w+[/w-]*/w+/.)*/w+"
s = "http://www.kingsley-hughes.com is a valid web address. And so is "
s = s & vbCrLf & "http://www.wrox.com. And "
s = s & vbCrLf & "http://www.pc.ibm.com - even with 4 levels."
MsgBox re.Replace(s, "** TOP SECRET! **")
上面这段代码的输出如图9-19所示。
图9-19
Replace方法还可以替换模式中的子表达式。这需要在用于替换的文本中使用特殊字符$1、$2等。这些“参数”就是记住的匹配结果。
7 Backreferencing
一个被记住的匹配结果就是模式的一部分。这就是所谓的backreferencing。需要用圆括号指定需要存储在临时缓存中的部分。每个捕获到的匹配结果都会按匹配到的先后次序存放(在正则表达式模式中从左到右)。存放匹配结果的缓存从1开始编号,最大可以到99。可以依次用$1、$2之类的变量访问它们。
可以用非捕获元字符("?:"、"?="或"?!")跳过正则表达式中的某些部分。
接下来的例子,前5个单词(由一个或多个非空白字符组成)会被记住,然后只有其中的4个会出现在替换文本中:
Dim re, s
Set re = New RegExp
re.Pattern = "(/S+)/s+(/S+)/s+(/S+)/s+(/S+)/s+(/S+)"
s = "VBScript is not very cool."
MsgBox re.Replace(s, "$1 $2 $4 $5")
这段代码的输出如图9-20所示。
图9-20
注意这段代码中为字符串中的每个代词都添加了一对(/S+)/s+。这使得代码能更好地控制所要处理的字符串。可以阻止字符串的尾部被添加到要显示的字符串中。要注意在使用backreferencing时要确保输出符合您的要求!
8 Test方法
Test方法对字符串执行正则表达式搜索,并返回一个布尔值说明匹配是否成功,用法见表9-8。
表9-8
代码 |
object.Test(string) |
对象 |
RegExp对象 |
字符串 |
正则表达式搜索的执行对象—— 必需的 |
如果匹配成功,Test方法返回True;否则返回False。这适用于判断字符串是否含有某个模式。注意,常常需要将模式设为大小写敏感,就像下面这个例子:
Dim re, s
Set re = New RegExp
re.IgnoreCase = True
re.Pattern = "http://(/w+[/w-]*/w+/.)*/w+"
s = "Some long string with http://www.wrox.com buried in it."
If re.Test(s) Then
MsgBox "Found a URL."
Else
MsgBox "No URL found."
End If
这段代码的输出如图9-21所示。