Python Discord机器人审查功能:搜索特殊字符||时遇错误
问题描述
我用Python开发了一个Discord机器人,用来检测黑名单触发词并审查内容。基础功能正常,但被Discord spoiler标签(||包裹)的词会出问题。我想先定位||的位置,只审查没被包裹的词,但定位时遇到了麻烦。
理想输入输出
- 输入:
"Omg I'm so dead" - 输出:
"Omg I'm so d||ead||"(当前可正常运行) - 输入:
"||Omg I'm so dead||" - 理想输出:
"||Omg I'm so dead||"(当前运行报错)
尝试过程
- 第一次使用以下代码:
censor_pos = [m.span() for m in re.finditer('||', mge, flags=0)]
因为|是正则特殊字符,返回了字符串的每个位置。
- 改用
re.escape()处理后:
censor_pos = [m.span() for m in re.finditer(re.escape('||'), mge, flags=0)]
出现错误:TypeError: expected string or bytes-like object, got 'NoneType'。打印censor_pos能得到正确位置,但后续执行触发错误。
完整代码
审查函数
def Censor_Trigger(mge, word): #function to censor trigger words given a message and a trigger word censor_pos = [m.span() for m in re.finditer(re.escape('||'), mge, flags=0)] #finds all instances of "||" to know which parts of message are censored trigger_pos = [m.span() for m in re.finditer(word, mge, flags=re.IGNORECASE)] #finds all instances of a trigger word, giving positions as tuples in an array censored_msg = mge print (censor_pos) print (trigger_pos) y = 0 #variable to account for position change when censoring multiple instances of the same word for x in trigger_pos: a = 0 is_censored = False for z in censor_pos: if 0<=a and (a+1)<(len(censor_pos)): if censor_pos[a][1]<=x[0]<=censor_pos[a+1][0]: is_censored = True return else: is_censored = False a=a+1 if is_censored == False: censored_msg = censored_msg[:x[1]+(y*4)] + "||" + censored_msg[x[1]+(y*4):] censored_msg = censored_msg[:(x[0]+1+(y*4))] + "||" + censored_msg[(x[0]+1+(y*4)):] y=y+1 print(censored_msg) else: return return censored_msg
调用代码
trigger_words = ["dead", "trigger", "example", "another"] #list of triggers for x in trigger_words: #runs the function to censor trigger words for all words in the trigger list Mess = Censor_Trigger(Mess, x)
完整错误信息
[2023-09-03 19:26:01] [ERROR ] discord.client: Ignoring exception in on_message Traceback (most recent call last): File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 441, in _run_event await coro(*args, **kwargs) File "C:\Users\user\Desktop\Discord Bot Fun\Test Code.py", line 17, in on_message Mess = Censor_Trigger(Mess, x) ^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\user\Desktop\Discord Bot Fun\Test Code.py", line 37, in Censor_Trigger censor_pos = [m.span() for m in re.finditer(re.escape('||'), mge, flags=0)] #finds all instances of "||" to know which parts of message are censored ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\re\__init__.py", line 223, in finditer return _compile(pattern, flags).finditer(string) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: expected string or bytes-like object, got 'NoneType'
解决方案
1. 修复NoneType错误根源
错误核心是:函数检测到触发词在||包裹区域内时,直接执行空return(无返回值,即返回None),后续循环调用时Mess被赋值为None,导致下一次调用re.finditer时传入None触发错误。
把函数中所有空return改成返回当前的censored_msg,比如:
if censor_pos[a][1]<=x[0]<=censor_pos[a+1][0]: is_censored = True return censored_msg # 返回原消息而非空值
2. 修正包裹区域判断逻辑
原逻辑仅检查触发词是否在第a和a+1个||之间,未处理奇数个||、多组包裹区间的情况。正确做法是先将||位置两两配对成完整包裹区间,再判断触发词是否在任意区间内。
3. 优化后的完整函数
import re def Censor_Trigger(mge, word): # 先处理空输入/None的情况 if not mge: return mge # 获取所有||的位置并两两配对成包裹区间 censor_spans = [m.span() for m in re.finditer(re.escape('||'), mge)] wrapped_intervals = [] for i in range(0, len(censor_spans), 2): if i + 1 < len(censor_spans): wrapped_intervals.append((censor_spans[i][0], censor_spans[i+1][1])) # 获取所有触发词的位置 trigger_spans = [m.span() for m in re.finditer(word, mge, flags=re.IGNORECASE)] censored_msg = mge offset = 0 # 记录插入||导致的位置偏移量,每次插入增加4个字符 for trigger_start, trigger_end in trigger_spans: # 调整触发词位置,适配之前插入操作带来的字符串长度变化 adjusted_start = trigger_start + offset adjusted_end = trigger_end + offset # 判断触发词是否被包裹 is_wrapped = False for wrap_start, wrap_end in wrapped_intervals: if wrap_start <= adjusted_start and adjusted_end <= wrap_end: is_wrapped = True break if not is_wrapped: # 在触发词前后插入||,比如dead → d||ead|| censored_msg = censored_msg[:adjusted_end] + "||" + censored_msg[adjusted_end:] censored_msg = censored_msg[:adjusted_start + 1] + "||" + censored_msg[adjusted_start + 1:] offset += 4 # 更新偏移量 return censored_msg
测试效果
- 输入
"Omg I'm so dead"→ 输出"Omg I'm so d||ead||" - 输入
"||Omg I'm so dead||"→ 输出"||Omg I'm so dead||" - 输入
"dead ||dead|| dead"→ 输出"d||ead|| ||dead|| d||ead||"
内容的提问来源于stack exchange,提问作者Asher
相关产品推荐
相关产品推荐

