fix(country-rule): 将国家规则正则引擎从 RE2 切换为 PCRE,支持零宽断言 - #289
Merged
Conversation
国家规则的匹配模式字段使用 Go 标准库 regexp(RE2 引擎),不支持零宽断言
(lookahead/lookbehind),导致 mihomo 用户常用的边界匹配写法编译失败:
(?<![A-Za-z])HK(?![A-Za-z])
→ error parsing regexp: invalid named capture: (?<...
这迫使用户使用裸子模式(如 (?i)香港|HK|Hong Kong),无法表达「两侧非字母边界」
语义,导致 SHK Premium、HKG(广岛 IATA 代码)等节点名误匹配 HK 规则。
改动:
- models/country_rule.go: import 从标准库 regexp 改为
github.com/dlclark/regexp2/v2/compat(PCRE 引擎的标准库兼容适配器)
- 所有调用点零改动:compat 子包的 Compile 返回 (*Regexp, error)、
MatchString 返回 bool,签名与标准库完全一致
- 不新增 module:mihomo 已传递依赖 dlclark/regexp2/v2 v2.2.1(go.mod indirect)
兼容性:
- 所有现有合法 pattern 行为不变(含 (?i) 内联标志、\s*、emoji、分组、量词)
- fix 只放开引擎能力,不自动改写用户已有规则;用户如想解决 SHK Premium/HKG
误匹配,需手动把 HK 规则 pattern 改为 (?<![A-Za-z])HK(?![A-Za-z])|香港|... 形式
测试(models/models_regexp2_test.go 新增):
- TestRegexp2Lookbehind: 7 个零宽断言用例,覆盖 issue ZeroDeng01#270 的 SHK Premium 场景
- TestRegexp2InlineFlags: 4 个老格式兼容性用例
- 现有 TestCountryRulePatternMatching 的 16 条 RE2 pattern 全部仍 PASS
实测验证:
- go test ./models/... 全部 PASS(golang:1.26.4 容器)
- 部署到生产实例实测 API /country-rules/test:
(?<![A-Za-z])HK(?![A-Za-z]) 对 HK→true、SHK Premium→false、HKG→false
- Web UI 编辑规则对话框零宽断言 pattern 实测通过
- batch-test 51 条启用规则 × 14 个节点名解析正确,无回归
Closes ZeroDeng01#270
isdoge
force-pushed
the
fix-country-rule-regexp
branch
from
August 18, 2026 17:04
f227ed4 to
948a5db
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
国家规则的「匹配模式」字段目前使用 Go 标准库
regexp(RE2 引擎),不支持零宽断言(lookahead/lookbehind),导致 mihomo 用户常用的边界匹配写法在 sublinkPro 中编译失败:RE2 报错:
error parsing regexp: invalid named capture: (?<...)这迫使用户使用裸子模式(如
(?i)香港|HK|Hong Kong),无法表达「两侧非字母边界」语义,导致:SHK Premium误匹配 HK 规则(左侧 S 是字母,应不匹配)HKG(广岛 IATA 代码)误匹配 HK 规则(右侧 G 是字母,应不匹配)issue #270 报告的正是这个误匹配问题。
修复
将正则引擎从 Go 标准库
regexp(RE2)切换为github.com/dlclark/regexp2/v2/compat(PCRE):(?=...)、(?!...)、(?<=...)、(?<!...)regexp完全一致(Compile返回(*Regexp, error),MatchString返回bool),所有调用点零改动dlclark/regexp2/v2 v2.2.1(见go.modindirect),无需在go.mod新增条目关键改动
文件变更
models/country_rule.go(+15/-27 行,单文件)models/models_regexp2_test.go(新增回归测试)兼容性
所有现有合法 pattern 行为不变(包括 issue #270 提到的误匹配场景的旧表现也保留,fix 只放开引擎能力,不自动改写用户配置):
SHK PremiumHK-001Hong Kong ServerUnited States日本节点用户如想彻底解决
SHK Premium/HKG误匹配,需手动把 HK 规则的 pattern 改为(?<![A-Za-z])HK(?![A-Za-z])|香港|Hong Kong|🇭🇰之类形式 —— 这是 issue #270 提到的用户配置层面的 fix,本 PR 只是把这个选项打开。实测证据
1. Web UI 编辑规则对话框(NAS sublinkpro 生产实例实测)
部署 fix 镜像
sublink-pro:fix-regexp-compat后,在国家规则编辑对话框中用零宽断言 pattern(?<![A-Za-z])HK(?![A-Za-z])实测:SHK Premium → ✗ 未匹配(左侧断言生效,fix 解决 baseline 误匹配 bug)

HKG → ✗ 未匹配(右侧断言生效)

HK → ✓ 匹配成功(纯 HK 两侧都是边界,正常用例不破坏)

2. API 实测(baseline vs fix 对比)
baseline(
zerodeng/sublink-pro:latest,RE2 引擎):fix(本 PR,PCRE 引擎):
3. Go 单元测试(含 16 条现有 pattern 兼容性回归)
TestCountryRulePatternMatching(已存在):16 条现有 RE2 pattern 全部仍 PASS(兼容性回归保护)TestRegexp2Lookbehind(新增):7 个零宽断言用例,覆盖 issue [Bug]: 国家规则 对 正则支持不完善 #270 的SHK Premium误匹配场景TestRegexp2InlineFlags(新增):4 个(?i)内联标志 +\s*+ emoji + 分组兼容性用例4. 真实数据 batch-test(51 条启用规则 × 14 个仿真节点名)
POST /api/v1/country-rules/batch-test返回符合预期:HK/HK01/HK Premium 01/香港 01/Hong Kong Server/🇭🇰 节点→ 全部正确解析为 HKSHK Premium/HKG-001→ 仍匹配 HK(这是预期行为:旧规则 pattern 未改,零宽断言需要用户手动配置)测试
go test ./models/...全部 PASS(NAS golang:1.26.4 容器内)(?i)内联标志 +\s*+ emoji + 分组兼容性 4 条 PASS部署 / 升级说明
SHK Premium/HKG误匹配,需手动编辑 HK 规则 pattern 为:技术细节
为什么用
dlclark/regexp2/v2/compat而不是主包?v2 主包
MatchString返回(bool, error),与标准库regexp.MatchString返回bool签名不同。所有调用点都要改成matched, _ := re.MatchString(s)的形式。compat子包提供了与标准库regexp完全一致的 API(Compile、MustCompile、MatchString、FindString等),调用点零改动,未来切换其他 PCRE 引擎只需改一行 import。为什么不新增 module?
mihomo(核心依赖)已传递依赖github.com/dlclark/regexp2/v2 v2.2.1(见go.modindirect 块),compat子包共享同一个 module,无需新增任何 require 条目。🤖 Generated with Claude Code