Python中bytes转字符串后正则匹配返回空列表的原因与修复方案
问题产生原因
直接对bytes类型对象调用str()做转换,并不会将bytes按照指定编码解码为可读的普通字符串,而是会生成bytes对象的字面量表示字符串:
- 转换后的字符串会自带开头的
b'和结尾的'标记 - 原bytes里的换行、空格等空白字符会以转义序列(比如
\n、\x20)的形式存在,不是实际的空白字符 - 部分特殊字节会被转义为
\x开头的十六进制转义形式,和正则匹配要求的原始文本格式完全不一致
这就是为什么手动定义的普通字符串s能被正则命中,而str(full_ast.stdout)得到的字符串匹配结果为空。
修复方法
- 替换错误的bytes转字符串逻辑,用bytes自带的
decode()方法按输出编码解码,clang的AST输出默认使用utf-8编码:# 错误写法 # s_full_ast = str(full_ast.stdout) # 正确写法 s_full_ast = full_ast.stdout.decode("utf-8") - (可选优化)修正subprocess调用和正则的鲁棒性问题:
- 开启
shell=True时直接传入命令字符串即可,不需要把命令包成列表,避免参数解析错误 - 正则里写死7位十六进制地址长度容易因为clang版本、运行环境不同漏匹配,可以把地址匹配段从
[a-f0-9]{7}改成[a-f0-9]+适配任意长度的内存地址
- 开启
修正后的完整program.py代码如下:
import subprocess as subs import re file = "simple.cpp" # shell=True时直接传命令字符串 full_ast = subs.run(f"clang -Xclang -ast-dump {file}", shell=True, stdout=subs.PIPE) s = ("test | |-UsingDirectiveDecl 0x16de688 <line:58:3, col:24> col:24 Namespace 0x16de588 '__debug' test\n" "test |-UsingDirectiveDecl 0x1e840b8 <simple.cpp:2:1, col:17> col:17 Namespace 0x1378e98 'std' test") # 优化正则适配任意长度地址 pattern = r"UsingDirectiveDecl\s0x[a-f0-9]+\s+<simple\.cpp:[0-9]+:[0-9]+,\s[a-zA-Z]+:[0-9]+>\s[a-zA-Z]+:[0-9]+\sNamespace\s0x[a-f0-9]+\s'[^']*'" s_full_ast = full_ast.stdout.decode("utf-8") namespace_s = re.findall(pattern, s_full_ast) print(namespace_s)
注:运行前请确保当前环境可以直接调用clang命令,否则会因为拿不到AST输出导致匹配为空。
内容的提问来源于stack exchange,提问作者BillaBong Jr.
相关产品推荐
相关产品推荐

