使用正则表达式提取多行SAS代码的Python实现问题求助
我明白你遇到的问题了——处理单行SAS宏时正则没问题,但多行宏就抓不到内容,这其实是正则默认行为和你原来的表达式结构导致的。让我一步步帮你解决:
首先,你原来的正则里硬写了\n来分隔行,这就限制了只能匹配中间只有一行的宏。更关键的是,Python的re模块默认下,.是不匹配换行符的,所以即使你加了*或+,也没法跨多行匹配内容。这时候re.DOTALL修饰符就派上用场了,它能让.匹配包括换行在内的所有字符。
接下来,我们需要调整正则表达式,让它能灵活匹配带参数/不带参数、多行内容、以及%mend后面可能带宏名的情况(SAS允许%mend;或%mend macro_name;两种写法)。
这里给你一个可以正常工作的实现:
import re # 示例SAS代码,包含多行宏和单行宏 sas_code = """ %macro process_data(input_ds, threshold); data filtered; set &input_ds.; if value > &threshold. then output; run; proc freq data=filtered; tables category; run; %mend process_data; %macro hello(); %put Hello from simple macro!; %mend; """ # 构建正则模式,使用re.DOTALL修饰符 macro_pattern = re.compile( r"%macro\s+(\w+)\s*(?:\((.*?)\))?\s*;(.*?)\s*%mend\s*(?:\w+)?\s*;", re.DOTALL ) # 提取所有宏定义 macro_matches = macro_pattern.findall(sas_code) # 遍历结果并打印 for macro_name, macro_params, macro_content in macro_matches: print(f"=== 宏名称: {macro_name} ===") print(f"参数: {macro_params.strip() if macro_params else '无参数'}") print("宏内容:") print(macro_content.strip()) print("\n" + "-"*60 + "\n")
让我拆解一下这个正则的关键部分:
%macro\s+(\w+): 匹配%macro关键字,捕获后面的宏名称到第一个分组。\s*(?:\((.*?)\))?: 匹配可选的参数列表,用非捕获组(?:...)包裹,里面的(.*?)捕获参数内容,?表示参数部分是可选的(支持无参数宏)。\s*;: 匹配宏定义行末尾的分号,前后允许有空格。(.*?): 非贪婪匹配宏的所有内容(包括换行),直到遇到%mend。\s*%mend\s*(?:\w+)?\s*;: 匹配%mend关键字,后面可选的宏名称,最后是分号,前后允许空格。
注意事项:
- 非贪婪匹配
.*?:一定要用非贪婪模式,否则会从第一个%macro一直匹配到最后一个%mend,把所有宏都当成一个内容。 - 嵌套宏的情况:如果你的SAS代码里有嵌套宏(一个宏里定义另一个宏),这个正则会失效,因为它会匹配到第一个
%mend。这种复杂场景建议用专门的SAS语法解析工具,而不是正则。但大多数情况下,SAS宏不会嵌套,这个正则足够用。 - 空白处理:正则里的
\s*可以处理代码中各种多余的空格、制表符或换行,让匹配更鲁棒。
内容的提问来源于stack exchange,提问作者Westworld
相关产品推荐
相关产品推荐

