# RegExMatch() [v1.0.45+]

判断字符串是否包含某个匹配模式(正则表达式).

    FoundPos := RegExMatch(Haystack, NeedleRegEx , OutputVar, StartingPos := 1)

## 参数

Haystack

  源字符串.

NeedleRegEx

  要搜索的模式, 它是兼容 Perl 的正则表达式(PCRE). 模式的选项(如果有) 必须放在模式字符串的开始且后面跟着闭括号. 例如, 模式 i)abc.*123 将匹配不区分大小写的 "abc", 接着零个或多个任意字符, 并以 "123" 结尾的字符串. 如果不含选项, 则可以省略 ")"; 例如, )abc 等同于 abc.

OutputVar

  模式 1(默认): 指定一个变量, 用来保存与整个模式匹配的 Haystack 的部分. 如果没有找到模式(即如果函数返回 0), 则此变量和下面的所有数组元素都被置空.

  如果在 NeedleRegEx 中包含捕获子模式, 那么它们的匹配将被存储在基名称为 OutputVar 的伪数组里. 例如, 如果输出变量名是 Match, 则匹配首个子模式的子字符串存储在 Match1, 第二个存储在 Match2, 依此类推. 这种情况的例外是命名子模式: 它们以名称而不是数字保存. 例如, 匹配命名子模式 (?P<Year>\d{4}) 的子字符串存储在 MatchYear. 如果特定的子模式不匹配任何文本(或如果函数返回零), 则相应的变量被置空.

  在函数中, 要创建全局而不是局部的伪数组, 则必须在使用前声明伪数组的基名称(例如 Match) 为全局变量. 对于假设全局函数, 反之亦成. 但是, 通常需要对每个变量都进行声明, 因为可能会造成混乱的根源.

  模式 2(位置和长度): 如果在正则表达式选项中含有 P(例如 P)abc.*123, 则整个模式的匹配字符串的 长度 会被存储到 OutputVar(如果没有匹配则为 0). 如果包含捕获子模式, 则它们匹配的位置和长度会被存储到两个伪数组: OutputVarPos 和 OutputVarLen. 例如, 如果变量的基名称为 Match, 首个子模式的匹配 位置(基于 1) 会存储在 MatchPos1, 而它的长度存储在 MatchLen1(如果子模式没有匹配或函数返回 0 则它们两者中保存的都为零). 这种情况的例外是命名子模式: 它们以名称而不是数字保存(例如 MatchPosYear 和 MatchLenYear).

  模式 3(匹配对象) [v1.1.05+]: 如果在正则表达式选项中含有大写的 O(例如 O)abc.*123), 则匹配对象会被存储到 OutputVar. 此对象还可以用来获取整个匹配和每个捕获子模式(如果存在) 的位置, 长度和值.

StartingPos

  如果省略 StartingPos, 则它默认为 1(从 Haystack 的首个字符开始). 否则, 从第二个字符开始请指定 2, 第三个开始为 3, 依此类推. 如果 StartingPos 超过了 Haystack 的长度, 则搜索会从 Haystack 末尾后的空字符串开始(这通常会导致没有匹配发生).

  如果 StartingPos 小于 1, 则它被视为从 Haystack 末尾开始的偏移. 例如, 0 表示从最后一个字符开始, 而 -1 则从倒数第二个字符开始. 如果 StartingPos 超出了 Haystack 最左边的位置, 则会搜索整个 Haystack.

  不论 StartingPos 的值是多少, 返回的值总是相对于 Haystack 的第一个字符. 例如, "abc" 在 "123abc789" 中的位置总是 4.

## 返回值

函数返回在字符串 Haystack 中最左边出现 NeedleRegEx 的位置. 位置 1 表示第一个字符. 0 表示没有找到匹配. 如果发生错误(比如 NeedleRegEx 出现语法错误), 将返回空字符串同时 ErrorLevel 被设为下面列表中除了 0 之外的值.

## 错误处理

[v1.1.04+]: 此函数失败时会抛出异常(这个不会和 "没有找到匹配" 冲突, 失败表示匹配过程中遇到问题, 而 "没有找到匹配" 表示匹配过程成功完成只是没有发现匹配). 想了解更多信息, 请参阅运行时错误.

ErrorLevel 被设置为下列值的其中一个:

- 0, 表示没有遇到错误.
- 一个如下格式的字符串: Compile error N at offset M: description. 在此字符串中, N 是 PCRE 错误值, M 是正则表达式中出现错误的字符的位置, 而 description 是描述这个错误的文本.
- 一个负数, 表示在正则表达式 执行 时遇到的错误. 尽管这样的错误很罕见, 然而像这些情况就容易出现这种错误, 例如 "太多空字符串匹配"(-22), "递归太深"(-21) 以及 "达到匹配限制"(-8). 如果出现这些情况, 请尝试重新设计更严格的匹配模式, 例如无论是否可行都把每个 * 替换为 ?, + 或像 {0,3} 这样的限制.

## 选项

请参阅选项了解修饰符, 例如 i)abc, 里面的选项关闭了 "abc" 模式中的区分大小写匹配.

## 匹配对象 [v1.1.05+]

如果在正则表达式选项中含有大写的 O, 则匹配对象会被存储到 OutputVar. 此对象含有下列方法和属性:

Match.Pos(N): 返回整个匹配或捕获子模式的位置.

Match.Len(N): 返回整个匹配或捕获子模式的长度.

Match.Value(N): 返回整个匹配或捕获子模式.

Match.Name(N): 返回指定的子模式的名称(如果它含有).

Match.Count(): 返回所有子模式的数目.

Match.Mark(): 适用时返回上次遇到 (*MARK:NAME) 的 NAME.

Match[N]: 如果 N 为 0 或有效的子模式编号或名称, 那么它相当于 `Match.Value(N)`. 否则, N 可以为上面其中一个方法的名称. 例如, `Match["Pos"]` 和 `Match.Pos` 相当于 `Match.Pos()`, 不过如果存在名称为 "Pos" 的子模式, 此时它们相当于 `Match.Value("Pos")`.

Match.N: 与上面相同, 不过这里 N 为未加引号的名称或编号.

对于上面的所有方法和属性, 其中 N 可以为下列值:

- 0 表示整个匹配.
- 子模式的编号, 包括含有名称的子模式.
- 子模式的名称.

如果指定了 N, 则可以使用方括号 [] 代替其中的圆括号.

## 性能

要在一个较大的字符串中搜索简单的子字符串, 请使用 InStr() 因为它比 RegExMatch() 更快.

为了提升性能, 最近使用的 100 个正则表达式会被缓存在内存中(以已编译的形式).

多次使用一个正则表达式时(例如在循环中), 使用研究选项(S) 可以提高性能.

## 备注

可以为子模式指定名称, 例如模式 (?P<Year>\d{4}) 中的 Year. 这种名称最多可以由 32 个字母数字和下划线组成. 下面的限制不适用于 "O"(匹配对象) 模式: 尽管命名的子模式在正则表达式运算时还可以使用它们的编号(例如 \1 为到实际匹配首个捕获子模式的字符串的后向引用), 然而它们被存储到输出伪数组时 只 通过名称(而不是编号). 例如, 如果 "Year" 是首个子模式, 则 OutputVarYear 会被设置为匹配的子字符串, 但 OutputVar1 不会发生变化(如果有则它会保持原来的值). 然而, 如果在 "Year" 后含有未命名子模式, 则它会被存储到 OutputVar2, 而不是 OutputVar1.

大多数字符(例如 abc123) 可以直接使用在正则表达式中. 然而, \.*?+[{|()^$ 这些字符则必须在其前面加上反斜杠来进行匹配. 例如, \. 表示一个原义的句点而 \\ 表示一个原义的反斜杠. 使用 \Q...\E 能避免转义. 例如: \QLiteral Text\E.

在正则表达式中, 特殊字符(如制表符和换行符) 可以使用一个重音符(`) 或反斜杠(\) 进行转义. 例如, 不含 x 选项时 `t 等同于 \t.

要了解正则表达式的基础(或复习正则表达式的语法), 请参阅正则表达式快速参考.

AutoHotkey 的正则表达式是使用来自 www.pcre.org 的兼容 Perl 的正则表达式(PCRE) 实现的.

[AHK_L 31+]: 在表达式中, `a ~= b` 能被当作 `RegExMatch(a, b)` 的缩写.

## 相关

RegExReplace(), 正则表达式快速参考, 正则表达式调出, InStr(), IfInString, StringGetPos, SubStr(), SetTitleMatchMode RegEx, 全局匹配和 Grep(论坛链接)

文本数据的常见来源: FileRead, UrlDownloadToFile, Clipboard, GUI Edit 控件

## 示例

有关普通 RegEx 的示例, 请参阅正则表达式快速参考.

报告 4, 这是找到匹配的位置.

    MsgBox % RegExMatch("xxxabc123xyz", "abc.*xyz")

报告 7, 因为 $ 要求在末端进行匹配.

    MsgBox % RegExMatch("abc123123", "123$")

报告 1, 因为通过不区分大小写选项实现了匹配.

    MsgBox % RegExMatch("abc123", "i)^ABC")

报告 1, 并把 "XYZ" 保存到 SubPat1.

    MsgBox % RegExMatch("abcXYZ123", "abc(.*)123", SubPat)

报告 7 而不是 1, 这是由于开始位置为 2 而不是 1.

    MsgBox % RegExMatch("abc123abc456", "abc\d+",, 2)

演示匹配对象的用法.

    FoundPos := RegExMatch("Michiganroad 72", "O)(.*) (?<nr>\d+)", SubPat)  ; 开始的 "O)" 将 SubPat 变成一个对象.
    Msgbox % SubPat.Count() ": " SubPat.Value(1) " " SubPat.Name(2) "=" SubPat["nr"]  ; 显示 "2: Michiganroad nr=72"

检索文件扩展名. 注意 SplitPath 也可以用于此目的, 而且更可靠.

    Path := "C:\Foo\Bar\Baz.txt"
    RegExMatch(Path, "\w+$", Extension)
    MsgBox % Extension  ; 显示 "txt".

类似于 Transform Deref, 下面的函数可以扩展包含在其他变量中的变量引用和转义序列. 此外, 这个例子还展示了如何在一个字符串中找到所有匹配项, 而不是停留在第一个匹配项(类似于 JavaScript 的 RegEx 中的 g 标志).

    var1 := "abc"
    var2 := 123
    MsgBox % Deref("%var1%def%var2%")  ; Reports abcdef123.

    Deref(String)
    {
        spo := 1
        out := ""
        while (fpo:=RegexMatch(String, "(%(.*?)%)|``(.)", m, spo))
        {
            out .= SubStr(String, spo, fpo-spo)
            spo := fpo + StrLen(m)
            if (m1)
                out .= %m2%
            else switch (m3)
            {
                case "a": out .= "`a"
                case "b": out .= "`b"
                case "f": out .= "`f"
                case "n": out .= "`n"
                case "r": out .= "`r"
                case "t": out .= "`t"
                case "v": out .= "`v"
                default: out .= m3
            }
        }
        return out SubStr(String, spo)
    }

dftg