如何在AutoIt中实现仅支持?和*通配符的高效字符串模式匹配函数(禁用正则表达式)
如何在AutoIt中实现仅支持?和*通配符的高效字符串模式匹配函数(禁用正则表达式)
我完全懂你的需求痛点:你需要一个只识别?(匹配任意单个字符)和*(匹配任意长度字符,包括空内容)的通配符匹配工具,但用正则表达式的话,模式里的其他特殊字符(比如.、+)会被当成正则语法解析,完全不符合你的预期;而且你要处理大量比较,所以效率必须跟上。
先说说你原来代码的问题:StringRegExp会把模式里的非通配符特殊字符当成正则元字符处理,比如如果你的模式是a.b,正则会把.解析成“任意单个字符”,但你其实只想匹配字面量a.b,这就会导致错误匹配。
下面是一个基于双指针迭代的高效实现,完全避开正则,只处理?和*两个通配符,同时支持大小写敏感开关:
Func iswm($string, $pattern, $caseSensitive = 1) ; 处理大小写不敏感的情况 If Not $caseSensitive Then $string = StringLower($string) $pattern = StringLower($pattern) EndIf Local $sLen = StringLen($string) Local $pLen = StringLen($pattern) Local $sPtr = 1 ; 字符串遍历指针 Local $pPtr = 1 ; 模式遍历指针 Local $starPos = -1 ; 记录最近一次遇到*的位置 Local $matchPos = 0 ; 记录*对应的字符串匹配起始位置 While $sPtr <= $sLen ; 情况1:当前模式字符是?,或与字符串字符完全匹配,同时前进两个指针 If $pPtr <= $pLen And (StringMid($pattern, $pPtr, 1) = "?" Or StringMid($pattern, $pPtr, 1) = StringMid($string, $sPtr, 1)) Then $sPtr += 1 $pPtr += 1 ; 情况2:当前模式字符是*,记录位置后只前进模式指针 ElseIf $pPtr <= $pLen And StringMid($pattern, $pPtr, 1) = "*" Then $starPos = $pPtr $matchPos = $sPtr $pPtr += 1 ; 情况3:之前遇到过*,回溯到*的下一个位置,尝试让*匹配更多字符 ElseIf $starPos <> -1 Then $pPtr = $starPos + 1 $matchPos += 1 $sPtr = $matchPos ; 情况4:没有匹配上,也没有*可以回溯,直接返回不匹配 Else Return 0 EndIf Wend ; 处理模式末尾剩余的*(比如模式是"abc*",字符串是"abc",应该匹配) While $pPtr <= $pLen And StringMid($pattern, $pPtr, 1) = "*" $pPtr += 1 Wend ; 如果模式指针走完了整个模式,说明完全匹配 Return $pPtr > $pLen ? 1 : 0 EndFunc
测试你的示例场景:
ConsoleWrite(iswm("hello whale", "?ello *", 1) & @CRLF) ; 输出1,匹配成功 ConsoleWrite(iswm("hello whale", "?ello w?al*", 1) & @CRLF) ; 输出1,匹配成功
额外测试场景(验证特殊字符不被错误解析):
; 模式里的.是普通字符,只有?是通配符 ConsoleWrite(iswm("a.b", "a?b", 1) & @CRLF) ; 输出1(?匹配.) ConsoleWrite(iswm("aab", "a.b", 1) & @CRLF) ; 输出0(.是普通字符,和a不匹配) ; *匹配任意长度字符,大小写不敏感 ConsoleWrite(iswm("TEST123ABC", "test*abc", 0) & @CRLF) ; 输出1,匹配成功
这个算法的核心优势:
- 无正则干扰:完全自定义处理
?和*,其他所有字符都按字面量匹配,不会出现意外解析 - 高效:线性时间复杂度O(n+m),n是字符串长度,m是模式长度,适合大规模批量比较
- 鲁棒性:处理了各种边界情况,比如模式开头/结尾是*、多个连续*、空字符串匹配等
备注:内容来源于stack exchange,提问作者user24511835
相关产品推荐
相关产品推荐

