MicroPython线程中re.search触发递归深度超限错误排查与解决
问题描述
由于MicroPython未提供re.findall(),自行实现了如下替代函数:
def findAll(pattern, s, flags = 0): found = [] while True: m = re.search(pattern, s, flags) if m: g = m.groups() s = s[m.span()[1]:] found.append(g[0] if len(g) == 1 else g) else: return found
该函数在CPython及MicroPython单线程环境下测试正常,但在Pico-W的子线程中调用时触发异常:
File "src/platforms/utils.py", line 16, in findAll RuntimeError: maximum recursion depth exceeded
(第16行对应循环内的m = re.search(...)语句)
使用的正则模式为'\x01\x05\x02(.+)\x03\x04',待匹配字符串是该模式的一次或多次重复,中间包含类JSON结构的字符串。
原因分析
- MicroPython的
re模块在子线程环境下的栈空间分配有限,正则匹配过程中的递归回溯更容易触达深度限制。 - 模式中的
.+是贪婪匹配,当待匹配内容包含嵌套结构(如类JSON的括号、引号)时,re.search会产生大量回溯递归调用,在子线程的有限栈资源下直接触发超限。 - 每次循环截取字符串
s = s[m.span()[1]:]的操作,若正则边界匹配存在模糊性,可能导致re.search反复处理相似区域,间接累积递归深度。
解决方法
- 优化正则模式,减少回溯
将贪婪匹配的.+改为非贪婪匹配.+?,精准限定匹配边界,避免不必要的递归回溯:
pattern = '\x01\x05\x02(.+?)\x03\x04'
- 重构循环逻辑,避免字符串截取
使用re.search的pos参数指定匹配起始位置,替代字符串截取操作,减少内存开销和潜在的匹配异常:
def findAll(pattern, s, flags=0): found = [] pos = 0 str_len = len(s) while pos < str_len: m = re.search(pattern, s, flags, pos) if m: g = m.groups() found.append(g[0] if len(g) == 1 else g) pos = m.span()[1] else: break return found
- 临时调整递归深度限制(应急方案)
在子线程初始化时,适当提高递归深度上限(注意Pico-W内存有限,数值不宜过大):
import sys sys.setrecursionlimit(1000) # 默认值通常为500左右,按需调整
- 拆分长字符串后逐个匹配
先按结束边界\x03\x04拆分待匹配字符串,再逐个片段匹配,降低单次正则匹配的复杂度:
def findAll(pattern, s, flags=0): found = [] segments = s.split('\x03\x04') for seg in segments: if seg: full_seg = seg + '\x03\x04' m = re.match(pattern, full_seg, flags) if m: g = m.groups() found.append(g[0] if len(g) == 1 else g) return found
内容的提问来源于stack exchange,提问作者resurrected user
相关产品推荐
相关产品推荐

