fix(monitor): 添加OCR昵称模糊匹配,支持形近字容错

问题:OCR把"草原探险服务器备用号"误识别为"草原深险服务器备用号",
导致精确匹配失败,昵称无法剥离,消息内容被污染。

修复:新增_fuzzy_find()静态方法,使用滑窗比较实现1字符编辑距离的容错匹配。
在全局匹配步骤中,当精确匹配失败时自动降级到模糊匹配。

测试验证:
✓ OCR形近字:"草原深险" -> "草原探险" 正确识别
✓ 含上下文:"你好草原深险服务器备用号有问题" 正确定位
✓ 正常匹配:精确匹配仍优先,无性能损耗
✓ 防误删:"服务器备用电源坏了" 不误匹配
This commit is contained in:
youpaishidifu
2026-08-16 13:30:59 +08:00
parent c06c7df065
commit 0b623fe098
+41 -5
View File
@@ -4765,6 +4765,31 @@ class MessageMonitor:
ts = re.sub(r'\s+', ' ', ts).strip().strip(',').strip()
return ts
@staticmethod
def _fuzzy_find(text: str, pattern: str, max_edits: int = 1) -> int:
"""在text中查找与pattern最多允许max_edits个编辑距离的子串(滑窗版)。
用于OCR误识别场景:如"草原探险"被识别为"草原深险",仅1字之差。
返回匹配起始位置,未找到返回-1。
"""
n, m = len(text), len(pattern)
if m == 0:
return 0
if n < m:
return -1
# 滑窗比较:每次移动一位,逐字符对比
for i in range(n - m + 1):
edits = 0
for j in range(m):
if text[i + j] != pattern[j]:
edits += 1
if edits > max_edits:
break
if edits <= max_edits:
return i
return -1
def _strip_qq_nickname(self, text: str) -> str:
"""从消息文本中剥离QQ用户昵称,防止昵称拼凑进消息文本导致查库关键词被压住。
@@ -4889,14 +4914,25 @@ class MessageMonitor:
# ⭐ 5) 全局匹配(兜底):昵称可能隐藏在文本中间
# 例:"=>草原探险服务器备用号游戏专用有问题" → 前缀匹配后剩"游戏专用有问题"
# 但有时前缀匹配失败,需要全局扫描
# ⭐ 2026-08-16: 添加OCR容错匹配——当精确匹配失败时,允许1字符差异
# 例:OCR把"草原探险服务器备用号"误识别为"草原深险服务器备用号"
if not changed: # 前缀匹配无变化时才进行全局匹配
# 按长度降序排序,优先匹配长昵称(避免短前缀误匹配)
for nick in sorted(nicknames, key=len, reverse=True):
if nick in ts:
start = ts.find(nick)
end = start + len(nick)
ts = (ts[:start] + ts[end:]).lstrip()
logger.debug(f"[qq] 全局匹配剥除昵称 {nick!r} @ [{start}:{end}]")
# 先尝试精确匹配
start = ts.find(nick)
if start >= 0:
ts = (ts[:start] + ts[start + len(nick):]).lstrip()
logger.debug(f"[qq] 全局匹配剥除昵称 {nick!r} @ [{start}:{start + len(nick)}]")
changed = True
break
# 精确匹配失败,尝试模糊匹配(OCR常见形近字误识别)
fuzzy_start = self._fuzzy_find(ts, nick, max_edits=1)
if fuzzy_start >= 0:
fuzzy_match = ts[fuzzy_start:fuzzy_start + len(nick)]
ts = (ts[:fuzzy_start] + ts[fuzzy_start + len(nick):]).lstrip()
logger.debug(f"[qq] 模糊匹配剥除OCR误识别昵称 {nick!r} -> {fuzzy_match!r} @ [{fuzzy_start}:{fuzzy_start + len(nick)}]")
changed = True
break