如何从不完整字符串中提取完整Python可解析对象
从不完整字符串中提取可解析的Python嵌套对象
需求说明
需要从API返回的可能不完整的字符串里,提取能被Python解析的完整字典、列表(包含嵌套结构):
- 完整字符串如
"[{'a' : 1, 'b' : 2}]",需提取整个列表[{'a' : 1, 'b' : 2}]; - 不完整字符串如
"[{'a' : 1, 'b' : 2}, {'a' : 1']",需提取其中完整的字典{'a' : 1, 'b' : 2},并整理为列表[{'a' : 1, 'b' : 2}]。
现有方案的问题
使用正则表达式无法处理嵌套结构——正则不支持递归匹配嵌套的{}/[],遇到多层嵌套时会失效。同时由于字符串不完整,直接用ast.literal_eval会抛出语法错误。
解决方案:基于栈的括号匹配
用栈来跟踪括号的嵌套层级,同时处理引号和转义字符,确保只识别结构层面的括号:
- 遍历字符串每个字符,跟踪是否处于引号中(避免误判引号内的括号);
- 遇到起始括号
{/[时,记录位置并压入栈; - 遇到结束括号
}/]时,弹出栈顶的起始括号,若栈为空则说明找到一个完整对象,截取对应区间的字符串; - 最后根据原字符串的格式(如是否以
[开头),将提取的对象整理成符合预期的格式。
代码实现
def extract_complete_objects(s): stack = [] start_indices = {} complete_objects = [] in_quote = None # 标记当前是否处于单/双引号中,值为None、"'"或'"' quote_escape = False # 标记是否遇到转义符 for idx, char in enumerate(s): # 处理转义字符 if quote_escape: quote_escape = False continue if char == '\\': quote_escape = True continue # 处理引号的进入/退出状态 if char in ("'", '"'): if in_quote == char: in_quote = None elif in_quote is None: in_quote = char continue # 处于引号中时,跳过括号处理 if in_quote is not None: continue # 处理起始括号 if char in ('{', '['): stack.append(char) start_indices[len(stack)] = idx # 处理结束括号 elif char in ('}', ']'): if not stack: continue # 无匹配的起始括号,直接忽略 opening_bracket = stack.pop() # 检查括号是否匹配 if (opening_bracket == '{' and char == '}') or (opening_bracket == '[' and char == ']'): if not stack: # 栈为空,说明找到一个完整的顶级对象 start_idx = start_indices[1] complete_obj = s[start_idx:idx+1] complete_objects.append(complete_obj) # 删除当前层级的起始位置记录 if len(stack) + 1 in start_indices: del start_indices[len(stack) + 1] # 整理输出格式:如果原字符串以[开头,且提取的是多个独立对象,组合成列表 if s.strip().startswith('[') and complete_objects: if not complete_objects[0].startswith('['): return f"[{', '.join(complete_objects)}]" # 单个对象直接返回,多个返回列表 return complete_objects[0] if len(complete_objects) == 1 else complete_objects
测试示例
# 测试完整列表 test1 = "[{'a' : 1, 'b' : 2}]" print(extract_complete_objects(test1)) # 输出:[{'a' : 1, 'b' : 2}] # 测试不完整列表 test2 = "[{'a' : 1, 'b' : 2}, {'a' : 1']" print(extract_complete_objects(test2)) # 输出:[{'a' : 1, 'b' : 2}] # 测试嵌套不完整列表 test3 = "[[1, 2, 3], [11, 12, 21]" print(extract_complete_objects(test3)) # 输出:[[1, 2, 3], [11, 12, 21]] # 测试嵌套字典 test4 = "{'name': 'Alice', 'info': {'age': 30, 'hobbies': ['reading', 'hiking']}, 'address': {" print(extract_complete_objects(test4)) # 输出:{'name': 'Alice', 'info': {'age': 30, 'hobbies': ['reading', 'hiking']}}
方案优势
- 完美支持多层嵌套的字典/列表;
- 正确识别引号内的括号(不会误判为结构括号);
- 处理转义引号,避免状态错误;
- 能从任意不完整字符串中提取所有可解析的完整对象。
内容的提问来源于stack exchange,提问作者Aaditya Ura
相关产品推荐
相关产品推荐

