最近看到一个群友(QQ群:144839730,加群请扫上面的二维码)的问题:如何提取宏调用的参数和参数值?这个问题用常规的字符函数可能要多行才能解决,用正则表达式就相对简单了,程序如下:
data demo;
STRING='%test(var1=123, var2=abc, var3=abc123);';
REX=prxparse('/(\w+\s*=\s*.+?[,\)])/');
START=1;
STOP=length(STRING);
call prxnext(REX, START, STOP, STRING, POSITION, LENGTH);
do while(POSITION > 0);
TEMP=substr(STRING, POSITION, LENGTH);
PARAM=scan(TEMP, 1, '=');
VALUE=substr(TEMP, length(PARAM)+2);
VALUE=prxchange('s/[\),]$//', -1, cats(VALUE));
output;
call prxnext(REX, START, STOP, STRING, POSITION, LENGTH);
end;
keep PARAM VALUE;
run;
我们可以看到上面的宏调用的参数值都是简单的字符,如果参数值中包含逗号上面的程序就不能用了。 比如下面这样的:
STRING='%test(var1=123, var2=%nrstr(NOTE: Y=Yes, N=No, U=Unkonw), var3=%nrstr(NOTE: (Y=Yes (or true))));';
这个时候我们就要先转换一下参数中的逗号,而借助正则表达式中的正向预查(?=...)
可以轻松完成,程序如下:
STRING=prxchange('s/,(?=[^\(]*\)[,\)])/~/', -1, STRING);
(?=...)
表示正向匹配,且不保存所匹配的内容。我们可以将它理解为自定义的边界(\b),这个边界位于表达式末。上面的表达式中[^\(]*
表示匹配非括号字符零次或多次,\)[,\)]
表示匹配),
或者))
,整个表达式的意思是只替换后面是),
或者))
的逗号,比如第一个逗号,因为后面有%nrstr(
,包含有(
,所以匹配不成功,逗号不会被替换。第二个逗号,因为后面有),
,所以匹配成功。
完整的程序如下:
data demo;
STRING='%test(var1=123, var2=%nrstr(NOTE: Y=Yes, N=No, U=Unkonw), var3=%nrstr(NOTE: (Y=Yes (or true))));';
STRING=prxchange('s/,(?=[^\(]*\)[,\)])/~/', -1, STRING);
REX=prxparse('/(\w+=.+?[,\)]+)/');
START=1;
STOP=length(STRING);
call prxnext(REX, START, STOP, STRING, POSITION, LENGTH);
do while(POSITION > 0);
TEMP=substr(STRING, POSITION, LENGTH);
PARAM=scan(TEMP, 1, '=');
VALUE=substr(TEMP, length(PARAM)+2);
VALUE=prxchange('s/[\),]$//', -1, cats(VALUE));
VALUE=prxchange('s/~/, /', -1, VALUE);
output;
call prxnext(REX, START, STOP, STRING, POSITION, LENGTH);
end;
keep PARAM VALUE;
run;