fix(monitor): 修复全局昵称匹配正则边界过严问题,改用简单子串匹配

原正则要求前后必须是空格/标点/字符串边界,导致常见OCR格式无法匹配:
- "你好草原探险服务器备用号,我想问" → 未剥离(失败)
- "=>草原探险服务器备用号游戏专用有问题" → 未剥离(失败)

新方案:统一使用最长优先的子串匹配
- 按昵称长度降序排序,优先匹配长昵称(避免短前缀误匹配)
- 直接字符串查找并移除,简单高效
- 不会误删部分匹配的文本(如"服务器备用电源"不会误删"备用")

测试验证:
✓ 纯昵称剥离
✓ 箭头前缀剥离
✓ 汉字前缀+逗号剥离
✓ 连续多个昵称剥离
✓ 短昵称剥离
✓ 防误删(部分匹配不误删)
This commit is contained in:
youpaishidifu
2026-08-16 12:12:09 +08:00
parent 91c027f5a1
commit 2175400744
+9 -23
View File
@@ -4890,29 +4890,15 @@ class MessageMonitor:
# 例:"=>草原探险服务器备用号游戏专用有问题" → 前缀匹配后剩"游戏专用有问题"
# 但有时前缀匹配失败,需要全局扫描
if not changed: # 前缀匹配无变化时才进行全局匹配
for nick in nicknames:
# 使用正则进行全局匹配,需要前后边界检查
# 避免误删正文中的正常文本(如"服务器备用"不应被误删)
pattern = re.compile(rf'(?:^|[^\w\u4e00-\u9fff]){re.escape(nick)}(?:$|[^а-яА-Яa-zA-Z0-9\u4e00-\u9fff])', re.UNICODE)
m_global = pattern.search(ts)
if m_global:
# 计算实际匹配范围(去除边界字符)
match_start = m_global.start()
match_end = m_global.end()
# 跳过开头的非单词字符
while match_start < len(ts) and not ts[match_start].isalnum() and ts[match_start] not in '\u4e00-\u9fff':
match_start += 1
# 跳过结尾的非单词字符
while match_end > match_start and not ts[match_end-1].isalnum() and ts[match_end-1] not in '\u4e00-\u9fff':
match_end -= 1
if match_start < match_end and match_start > 0: # 不在开头(已处理过)
before = ts[:match_start]
after = ts[match_end:]
ts = (before + after).lstrip()
logger.debug(f"[qq] 全局匹配剥除昵称 {nick!r}: {m_global.group()!r}")
changed = True
break
# 按长度降序排序,优先匹配长昵称(避免短前缀误匹配)
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}]")
changed = True
break
# ⭐ 群聊多消息拆分:OCR多条消息拼接时,[头衔]用户名 或 裸昵称 作为分隔符出现在文本中间
# 如 "C4炸弹起来准备测试了,[专业皮肤定制] C4炸弹,[专业皮肤定制] C4炸弹,youpaishidifu关于我们"