Telethon中替换消息指定词汇时如何调整文本实体的offset和length?
Telegram机器人关键词替换保留原有格式解决方案
核心问题原因
你之前修改event.message.entities后格式错位的核心原因是:Telegram消息实体的offset、length参数均按照UTF-16码位计算,并非普通UTF-8字符计数,替换词汇后长度变化如果没有按UTF-16标准重新计算偏移,就会出现格式错位。
具体实现步骤
- 第一步:深拷贝原始消息的纯文本内容与实体列表,不要直接修改
event对象的原始属性 - 第二步:先对纯文本做关键词替换,同时记录每个替换操作产生的偏移差:例如将长度为A的原词替换为长度为B的新词,需要将该替换位置之后所有实体的
offset统一加上(B的UTF-16码位长度 - A的UTF-16码位长度) - 第三步:如果替换的词汇本身被某个实体覆盖,需要同步调整该实体的
length参数:例如原词thisUTF-16长度为4,替换为testing后UTF-16长度为7,对应实体的length直接修改为7即可,不需要调整起始offset - 第四步:发送消息时同时传入替换后的纯文本、调整完成的实体列表,不需要指定
parse_mode参数,即可完全复现原始消息的格式
代码示例(Python python-telegram-bot v13.x 版本)
import copy def get_utf16_len(s: str) -> int: return len(s.encode('utf-16-le')) // 2 # 原始消息数据 raw_text = event.message.text raw_entities = copy.deepcopy(event.message.entities) replace_map = {"this": "testing", "keyboard": "mouse"} new_text = raw_text offset_adjust = 0 for old_word, new_word in replace_map.items(): start = new_text.find(old_word) while start != -1: # 计算偏移差 old_len = get_utf16_len(old_word) new_len = get_utf16_len(new_word) diff = new_len - old_len # 调整该位置之后的所有实体offset for ent in raw_entities: if ent.offset > start + offset_adjust: ent.offset += diff # 如果实体覆盖当前替换的词,调整实体长度 elif ent.offset <= start + offset_adjust and ent.offset + ent.length >= start + offset_adjust + old_len: ent.length += diff # 替换文本 new_text = new_text[:start] + new_word + new_text[start+len(old_word):] offset_adjust += diff # 查找下一个匹配词 start = new_text.find(old_word, start + len(new_word)) # 发送新消息 await event.respond(new_text, entities=raw_entities)
内容的提问来源于stack exchange,提问作者SAL
相关产品推荐
相关产品推荐

