如何忽略含嵌套括号的区域,按空格和冒号分割字符串?
解决嵌套括号场景下的键值对提取问题
问题分析
你需要从包含嵌套圆括号()和花括号{}的字符串中提取键值对,要求分割时忽略括号内部的空格和冒号。之前的正则无法处理嵌套括号,导致括号内的内容被误分割。
示例目标:从字符串
p1: I/out p2: (('mean', 5), 0.0, ('std', 2)) p3: 7 p4: {'name': 'check', 'value': 80.0}
中提取出:
- p1:
I/out - p2:
(('mean', 5), 0.0, ('std', 2)) - p3:
7 - p4:
{'name': 'check', 'value': 80.0}
方案1:使用支持递归的正则匹配(推荐用Python regex库)
标准Python的re模块不支持递归正则,但第三方regex库可以处理嵌套结构。安装后用以下正则直接匹配所有键值对:
import regex s = "p1: I/out p2: (('mean', 5), 0.0, ('std', 2)) p3: 7 p4: {'name': 'check', 'value': 80.0}" pattern = r'(\w+):\s*((?:[^(){}\s]+|\((?:(?R))*\)|\{(?:(?R))*\})+)' matches = regex.findall(pattern, s) # 转换为字典或列表 result = dict(matches) print(result)
输出:
{'p1': 'I/out', 'p2': "(('mean', 5), 0.0, ('std', 2))", 'p3': '7', 'p4': "{'name': 'check', 'value': 80.0}"}
正则说明:
(\w+):匹配键名(如p1、p2):\s*:匹配冒号和后续空格((?:[^(){}\s]+|\((?:(?R))*\)|\{(?:(?R))*\})+):匹配值部分,其中:[^(){}\s]+:匹配非括号非空格的内容\((?:(?R))*\):递归匹配圆括号内的所有内容(包括嵌套)\{(?:(?R))*\}:递归匹配花括号内的所有内容(包括嵌套)
方案2:手动解析(无第三方库依赖)
如果不想用第三方库,可以手动遍历字符串,跟踪括号的嵌套层级,确定分割点:
def extract_key_value_pairs(s): pairs = [] current_key = [] current_value = [] in_quotes = False bracket_stack = [] for char in s: # 处理引号(避免把引号内的括号当成嵌套) if char in ('"', "'"): in_quotes = not in_quotes current_value.append(char) continue if in_quotes: current_value.append(char) continue # 处理括号嵌套 if char in ('(', '{'): bracket_stack.append(char) current_value.append(char) continue if char in (')', '}'): if bracket_stack and ((char == ')' and bracket_stack[-1] == '(') or (char == '}' and bracket_stack[-1] == '{')): bracket_stack.pop() current_value.append(char) continue # 当不在括号内且遇到冒号:确定键 if char == ':' and not bracket_stack: current_key = ''.join(current_key).strip() current_value = [] continue # 当不在括号内且遇到空格:完成一个键值对 if char.isspace() and not bracket_stack: if current_key and current_value: pairs.append((current_key, ''.join(current_value).strip())) current_key = [] current_value = [] continue # 否则添加到当前内容 if current_key: current_value.append(char) else: current_key.append(char) # 处理最后一个键值对 if current_key and current_value: pairs.append((current_key, ''.join(current_value).strip())) return dict(pairs) s = "p1: I/out p2: (('mean', 5), 0.0, ('std', 2)) p3: 7 p4: {'name': 'check', 'value': 80.0}" print(extract_key_value_pairs(s))
输出和方案1一致,这个方法不需要依赖第三方库,且能处理任意深度的嵌套括号。
原正则的问题说明
你之前用的[\s:]+(?=[^\{\(\)\}]*(?:[\{\(]|$)),其前瞻部分只检查到下一个括号或字符串结尾,但没有考虑括号的闭合。当遇到(('mean', 5), 0.0, ('std', 2))时,0.0前面的空格处于括号内部,但前瞻会误判为可以分割的位置,因为它只看到前面的),没意识到整个外层括号还没闭合。
内容的提问来源于stack exchange,提问作者olivaw
相关产品推荐
相关产品推荐

