如何使用正则表达式提取带重复键与嵌套值的命令行键值对
命令行键值对提取解决方案
原有方案的问题
- 分开匹配键和值容易出现顺序错位,无法保证一一对应
- 仅匹配
${}开头的值会漏掉普通字符串、引号包裹的JSON等类型的值 - 用
\S+匹配无法识别包含空格的合法值(比如'Star - Trek')
匹配规律梳理
基于你提供的样例,符合标准命令行长选项规则:
- 所有键均以
--开头,键名本身不含空格 - 值分为三类:
- 单引号包裹的内容:可包含空格、嵌套JSON、特殊字符,直到闭合单引号为止
- 双引号包裹的内容:规则同单引号
- 无引号包裹的内容:为连续非空格字符,比如
${NAME}这类变量
- 选项之间用空白字符(空格、换行、行连接符
\)分隔
修正后的代码实现
import re import html # 注意不要用str作为变量名,会覆盖Python内置类型 raw_cmd = '''--client 'jENNY' \\ --url_to_use "${URL}" \\ --script 'path/to/my/script.py' \\ --name ${NAME} \\ --id ${ID} \\ --build ${BUILD} \\ --part 'Star - Trek' \\ --sequence_name 'test_sequence' \\ --task_parameters '{"ENV_VARS": {"SKIP": "1", "TEST": "1", "REUSE": "0"}, "ARGUMENTS": {"--mode": "test", "--bind": "True", "--skip_stats": "True"}, "NAME": "R_eCAp"}' \\ --task_parameters '{"TASK_ARGUMENTS": {"-t": "new/path/script.py", "--test": "'"${RESOURCE}"'", "-k": "ASpace2001Odessy"}, "NAME": "Run", "LAUNCH": {"TIMER": 42}}' \\ --custom 'r2d2.xml' \\ --task_parameters '{"NAME": "Posts", "ARGUMENTS": {"--priority": "P1"}}' ''' # 先转义HTML实体编码,把"转为正常双引号 processed_cmd = html.unescape(raw_cmd) # 匹配正则:支持跨行长选项、嵌套引号值、重复键 pattern = r'--(\S+?)\s+(?:\'(.*?)\'|"([^"]*?)"|(\S+))(?=\s+--|\s*$)' matches = re.findall(pattern, processed_cmd, re.DOTALL) # 整理键值对,保留重复键的顺序 kv_pairs = [] for key, val_single, val_double, val_naked in matches: # 取非空的对应值 value = val_single or val_double or val_naked kv_pairs.append((key.strip(), value.strip())) # 如果需要拆分成分开的keys、values数组 keys = [k for k, v in kv_pairs] values = [v for k, v in kv_pairs]
正则说明
--(\S+?):匹配--开头的键,非贪婪模式捕获不含--的键名\s+:匹配键值之间的任意空白字符(空格、换行、制表符)- 非捕获分组
(?:\'(.*?)\'|"([^"]*?)"|(\S+)):依次匹配单引号包裹值、双引号包裹值、无引号纯字符值 - 正向预查
(?=\s+--|\s*$):确认值的边界是下一个--开头的选项或者字符串结尾,避免越界匹配
注意事项
- 提取的
task_parameters值已经是完整JSON结构,后续可直接用json.loads()转换为Python字典 - 如果你的实际场景中存在单引号内嵌套转义单引号的情况,需要调整正则增加转义字符的匹配规则
内容的提问来源于stack exchange,提问作者Ayodele Ashad
相关产品推荐
相关产品推荐

