正则表达式之正向预查(?=...)

QQ

最近看到一个群友(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;
曾宪华 /
本文采用 署名-非商业性使用-相同方式共享 3.0许可协议 属于 程序人生 分类, 被贴了 PRXCHANGE Regular Expression 正则表达式 书签

上一篇 SAS自动打开数据集及复制变量值
下一篇 一道小学生的趣味数学题