# RegExMatch

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

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

## 参数

Haystack

  类型: 字符串

  要搜索其内容的字符串. 可能包含二进制零.

NeedleRegEx

  类型: 字符串

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

  虽然 NeedleRegEx 不能包含二进制零, 但模式 `\x00` 可用来匹配 Haystack 中的二进制零.

&OutputVar

  类型: VarRef

  指定一个变量引用, 在其中存储匹配对象, 可以用来获取整体匹配和每个捕获子模式(如果存在) 的位置, 长度和值.

  如果没有找到模式(也就是说, 如果函数返回 0), 这个变量将被置空.

StartingPos

  类型: 整数

  如果省略 StartingPos, 则它默认为 1(Haystack 的开始位置). 否则, 指定 2 从第二个字符开始, 3 从第三个字符开始, 以此类推. 如果 StartingPos 的长度超过 Haystack 的长度, 那么搜索将从 Haystack 末尾的空字符串开始(常结果是不匹配).

  指定负值的 StartingPos, 从右边的位置开始搜索. 例如, -1 从最后一个字符开始, -2 从倒数第二个字符开始. 如果 StartingPos 试图超出 Haystack 的左端, 则会搜索整个 Haystack.

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

## 返回值

类型: 整数

函数返回在字符串 Haystack 中最左边出现 NeedleRegEx 的位置. 位置 1 表示第一个字符. 如果没有找到模式, 则返回 0.

## 错误

语法错误: 如果模式中包含语法错误, 则抛出 Error, 并带有以下形式的消息: Compile error N at offset M: description. 在该字符串中, N 是 PCRE 中错误的编号, M 是正则表达式中违规字符的位置, 而 description 是描述该错误的文本.

执行错误: 如果在 执行 正则表达式的过程中发生错误, 则抛出 Error. 错误对象的 Extra 属性包含了 PCRE 的错误编号. 虽然这种错误很少发生, 但最有可能发生的是 ""太多空字符串匹配"(-22), "递归太深"(-21), 和 "达到匹配限制"(-8). 如果出现这些情况, 请尝试重新设计更严格的匹配模式, 例如无论是否可行都把每个 * 替换为 ?, + 或像 {0,3} 这样的限制.

## 选项

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

## 匹配对象(RegExMatchInfo)

如果找到了匹配, 一个包含匹配信息的对象将被存储在 OutputVar. 这个对象有以下方法和属性:

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

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

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

Match.Count: 返回所有子模式的数目(捕获组), 这也是 N 的最大值.

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

Match[] 或 Match[N]: 返回整个匹配或捕获子模式.

对于上面的所有, N 可以为下列值:

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

Match.N: Match["N"] 的简写, 其中 N 是任何未加引号的名称或数字, 其不能与定义的属性(上面列出) 冲突. 例如, `match.1` 或 `match.Year`.

该对象还支持枚举; 也就是说, 支持 for-loop. 或者, 可以使用 `Loop Match.Count`.

## 性能

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

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

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

## 备注

可以为子模式指定名称, 例如模式 (?P<Year>\d{4}) 中的单词 Year. 这种名称最多可以由 32 个字母数字和下划线组成. 请注意, 命名的子模式也是有编号的, 如果在 "Year" 后出现了一个未命名的子模式, 它将被存储在 `OutputVar[2]` 中, 而不是 `OutputVar[1]` 中.

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

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

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

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

在表达式中, `a ~= b` 能被当作 `RegExMatch(a, b)` 的缩写.

## 相关

RegExReplace, RegEx 快速参考, Regular Expression Callouts, InStr, SubStr, SetTitleMatchMode RegEx, Global matching and Grep (forum link)

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

## 示例

有关普通 RegEx 的示例, 请参阅 RegEx 快速参考.

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

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

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

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

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

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

报告 1, 并把 "XYZ" 保存到 SubPat[1].

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

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

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

演示匹配对象的用法.

    FoundPos := RegExMatch("Michiganroad 72", "(.*) (?<nr>\d+)", &SubPat)
    MsgBox SubPat.Count ": " SubPat[1] " " SubPat.Name[2] "=" SubPat.nr  ; 显示 "2: Michiganroad nr=72"

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

    Path := "C:\Foo\Bar\Baz.txt"
    RegExMatch(Path, "\w+$", &Extension)
    MsgBox Extension[]  ; 报告 "txt".

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

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

    Deref(Str)
    {
        spo := 1
        out := ""
        while (fpo:=RegexMatch(Str, "(%(.*?)%)|``(.)", &m, spo))
        {
            out .= SubStr(Str, spo, fpo-spo)
            spo := fpo + StrLen(m[0])
            if (m[1])
                out .= %m[2]%
            else switch (m[3])
            {
                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 .= m[3]
            }
        }
        return out SubStr(Str, spo)
    }

dftg