这个简短的教程将通过 StringRegExp() 函数来揭开正则表达式的神秘面纱。

StringRegExp( "测试字符串", "正则表达式" [, 标志 ] )

"测试字符串" = 用于搜索是否匹配正则表达式的字符串。
"正则表达式" = 由若干特殊字符组成的字符串,用以正好描述你的匹配规则。它没有 ifs, ands, 或 buts等逻辑关系。只能是匹配或不匹配。
标志 [可选项] = 用来告诉函数你是只想知道 "正则表达式"是否匹配,还是让它返回第一个匹配的部分,或者是返回所有的匹配项。


这很简单
你已经弄清楚了, "正则表达式" 字串是在调用StringRegExp()函数(以下简称:SRE)中最困难的部分。 我觉得最好这样去理解这个表达式:告诉函数这是匹配一个特定字符串的。 那么我们可以这样:如果你想匹配字符串"test",这应该很简单。你告诉SRE第一个搜索字符为"t"。如果发现,函数接着用上面的表达式匹配其余部分。如果下一个字符是“e",那么函数仍然认为是匹配的。假设接着出现的字母是 "x"。 SRE 立即认为不匹配,因为我们让它找的第三个字母是"s"。

示例 1
MsgBox(0, "SRE 示例1的结果", StringRegExp("text", 'test'))

在这个例子中,Msgbox对话框应该显示 "0",即在测试字符串"text"中没有发现正则表达式"test"。这个例子很简单,只是让你知道它为什么没有发现(不匹配)。

下面们来看一个特殊的表达式 ("[ ... ]")(...表示省略,并非表达式的一部分,"["和"]"可以称之为元字符,有的资料称为保留字符,正则表达式有很多类似这样的元字符,译者注)。 你可以把它视为逻辑或("OR")功能。接着前面的例子。如果我们想找的字符串是"test"或者"text"。那么,我们来想像一下 SRE 的思路:我想找的第一个字符是"t",然后是 "e", 这两个要同时匹配。接着我想找的是"s"或者是 "x",这时我们可以使用"[sx]",即不管是"s"或者是"x"都认为是匹配的。那最后一个要找的字符就是"t"了。

示例 2
MsgBox(0, "SRE 示例2的结果", StringRegExp("text", 'te[sx]t'))
MsgBox(0, "SRE 示例2的结果", StringRegExp("test", 'te[sx]t'))


这里的两个对话框应该都显示"1", 因为表达'te[sx]t'即匹配"text"同时也匹配"test"。

你可以指定每个字符的匹配次数,用"{匹配次数}",你也可以指定一个次数范围如"{n,m}"表示匹配n-m次。下面这个例子看起来是多余的,但这样更能表达我的意思:

示例 3
MsgBox(0, "SRE 示例3的结果", StringRegExp("text", 't{1}e{1}[sx]{1}t{1}'))
MsgBox(0, "SRE 示例3的结果", StringRegExp("aaaabbbbcccc", 'b{4}'))

并非如此简单
现在你大概在想"这不就是StringInStr()函数的功能吗?"。好的,当“标志”参数值为0时,大多数时候你这样想是对的。但是 SRE 的功能比你想像的要强大得多。当你使用 SRE 越多,你会发现你对正则表达式知道的越少。你希望对正则表达式的元字符(或称为保留字符)理解越来越精确。 来举个例子,在游戏的聊天记录里有这样一句: "你被怪物***造成18点伤害。" 你想知道怪物的***对你造成了多少伤害。这里你不能用StringInStr()因为你不知道你要找的数字是"18", 你要找的是"????",这是什么?你要找的是一个未知的数字。

这里我该怎样构造这个正则表达式呢,先看看你对你要找的东西有什么了解:
1) 你知道它无非是一些数字。
2) 你知道它有时候是2位数。
2a) 你从游戏中了解到,怪物对你的伤害值最大是999。
2b) 你还知道怪物的最小伤害值是0。
3) 那么你就知道了它的长度介于1至3个字符之间。
4) 你知道在整个测试字符串当中没有别的数字。

说到这里,我想引入"标志"的另一个值"1"和另一对元字符"()",可以称之为分组元字符。当“标志”为"1"时,SRE函数不仅进行表达式的正则匹配,而且还会返回一个数组,该数组的每个元素保存一个正则表达式中的“组”。看下面的示例:

示例 4
$asResult = StringRegExp("This is a test example", '(test)', 1)
If @error == 0 Then
MsgBox(0, "SRE 示例4的结果", $asResult[0])
EndIf

$asResult = StringRegExp("This is a test example", '(te)(st)', 1)
If @error == 0 Then
MsgBox(0, "SRE SRE 示例4的结果", $asResult[0] & "," & $asResult[1])
EndIf

很明显,第一段代码中的正则表达式匹配字符串的某处,SRE函数将匹配的结果保存在了返回的数组中。你也可以将表达式分组,就像示例4中的第二段代码那样。

Ok, 回到前面怪物的问题。现在我们知道怎样来"捕捉"文本。让我们来构造表达式:即然你知道要找的是一些数字,那么有3种方法。"需要匹配的数字":"[:digit:]", "[0-9]", 和 "\d"。 第一种方法是最容易理解的。关于表达式的几种属性(digit, alnum, space, 等等。 请参见帮助文件StringRegExp函数部分)你可以使用这些特殊的设置属性,其中的一种来表示数字。 "[0-9]"表示所有数字即从0到9。 "\d" 是指定特殊的字符属性(数字)和前2种方法类似。这三种方法没什么不同。通常 SRE 函数中尽量使用最小的规模来构建表达式。

首先,我们知道我们要捕捉的是一些数字,那么我们从一个括号"("开始构建我们的表达式。接着,我们要找的数字的长度在1-3个字符之间,那么现在我们的表达式看起来应该像这样"([0-9]{1,3}"。最后再用一个右括号来结束这个表达式的构建: "([0-9]{1,3})"。好了,来试试:

示例 5
$asResult = StringRegExp("你被怪物***造成18点伤害.", '([0-9]{1,3})', 1)
If @error == 0 Then
MsgBox(0, "SRE 示例5的结果", $asResult[0])
EndIf


试过了吗,对话框中是不是显示"18"。

下面,我们来了解一下 非捕获组。这时你需要在构建表达式中的分组时以"(?:" 开头,而不是 "("。 让我们再来看一下你的游戏 "你被36只怪物***造成279点伤害." 这时,你若还用示例5中的表达式,你会发现它只能捕获到"36"而非"279"。现在我们想知道这2个数字到底有什么区别。仔细观察,你会发现第二个数后面始终跟着"点伤害"这三个字。我们可以这样来修改我们的表达式"([0-9]{1,3}点伤害)",但我们脚本的目的只是为了找到伤害的点数,并不需要"点伤害"这三个字老是显示在返回的结果里面。怎么办?呵呵,我们可以使用非捕获组来完成它。

示例 6
$asResult = StringRegExp("你被36只怪物***造成279点伤害.", '([0-9]{1,3})(?:点伤害)', 1)
If @error == 0 Then
MsgBox(0, "SRE 示例6的结果", $asResult[0])
EndIf


罗嗦了这么多,我只是想让大家了解一些基础的东西,包括正则表达式是如何工作的,以及SRE函数的用法。请牢记以下几点:
- 有时间多想想正则表达式元字符的用法
- StringRegExp()函数是根据正则表达式来工作的,你只需要提供正确的正则表达式给它就行了
- 记住[ ... ]的用法,如[xyz] 可以匹配"x", "y", 或者"z"
如果你还有别的疑问,请先参考帮助文件。 那里面所述的语法都是围绕SRE函数的。仔细看一下,尤其是其中关于"字符重复"的一段。它可以使你写的表达式更加简练。例如: "*"可以代替{0,}同样表示匹配0次或更多次。

祝你好运,总之正则表达式可以大缩短代码的长度,更加便于脚本以后的编辑和修改。有任何错误或建议欢迎反馈!