fix(monitor): 添加OCR昵称模糊匹配,支持形近字容错
问题:OCR把"草原探险服务器备用号"误识别为"草原深险服务器备用号", 导致精确匹配失败,昵称无法剥离,消息内容被污染。 修复:新增_fuzzy_find()静态方法,使用滑窗比较实现1字符编辑距离的容错匹配。 在全局匹配步骤中,当精确匹配失败时自动降级到模糊匹配。 测试验证: ✓ OCR形近字:"草原深险" -> "草原探险" 正确识别 ✓ 含上下文:"你好草原深险服务器备用号有问题" 正确定位 ✓ 正常匹配:精确匹配仍优先,无性能损耗 ✓ 防误删:"服务器备用电源坏了" 不误匹配
This commit is contained in:
+41
-5
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user