使用prxmatch与DS2的SAS错误

时间:2018-07-11 14:41:20

标签: regex sas sas-ds2

在我看来,将prxmatch与SAS DS2一起使用时出现错误。我的代码也有可能出错。我想知道这个问题是因为我的代码还是SAS的编译错误。

在下面的代码中,我将一个数据表中的搜索词与另一个数据表中的搜索词进行匹配。

data master_table;
    input name $ search_text $;
    datalines;
Frank   allHere
John    Sales
Mary    Acctng
Joe     Findme
Sue     Hereiam
Jim     graccaa
;
run;

proc print data= master_table; run;

data search_term_table;
    infile datalines missover;
    input id $ search_term $;
datalines;
1   Here
2   Find
3   Acc
;
run;

proc ds2;
    data search_results (overwrite=yes);
    retain rc;
    dcl double rc c ;
    declare char(8) id N;
    declare char(11) name;
    declare char(1) c_options;
    declare char(20) search_term search_text;
    dcl package hash h(1, 'search_term_table');
    dcl package hiter hi('h');
        method init();
            rc = h.keys([id]);
            rc = h.data([id search_term]);
            rc = h.defineDone();
        end;
        method run();
            dcl double rc;
            set master_table;
            if _N_ = 1 then put 'ROW    ITEM';
            N = _N_;
            rc = hi.first();
            do while(rc=0);
                c_options = 'i';
                search_term = cats('/', search_term, '/', c_options);
                search_text = catx(' ', search_text);
                c = prxmatch(search_term, search_text);
                put N id 'prxmatch(' search_term ',' search_text '); ---> ' c;
                output;
                rc = hi.next();
            end;
        end;
    enddata;
run;
quit;

put语句的结果如下所示。

ROW 3 ITEM 1中找不到匹配项,因为它使用的是前一行最后一项而不是当前项的正则表达式。

ROW 5 ITEM 1中,情况相反。找不到匹配项,因为它再次使用了上一行最后一项中的正则表达式。

ROW    ITEM
1        1        prxmatch( /Here/i              , allHere              ); --->  4
1        2        prxmatch( /Find/i              , allHere              ); --->  0
1        3        prxmatch( /Acc/i               , allHere              ); --->  0
2        1        prxmatch( /Here/i              , Sales                ); --->  0
2        2        prxmatch( /Find/i              , Sales                ); --->  0
2        3        prxmatch( /Acc/i               , Sales                ); --->  0
3        1        prxmatch( /Here/i              , Acctng               ); --->  1
3        2        prxmatch( /Find/i              , Acctng               ); --->  0
3        3        prxmatch( /Acc/i               , Acctng               ); --->  1
4        1        prxmatch( /Here/i              , Findme               ); --->  0
4        2        prxmatch( /Find/i              , Findme               ); --->  1
4        3        prxmatch( /Acc/i               , Findme               ); --->  0
5        1        prxmatch( /Here/i              , Hereiam              ); --->  0
5        2        prxmatch( /Find/i              , Hereiam              ); --->  0
5        3        prxmatch( /Acc/i               , Hereiam              ); --->  0
6        1        prxmatch( /Here/i              , graccaa              ); --->  3
6        2        prxmatch( /Find/i              , graccaa              ); --->  0
6        3        prxmatch( /Acc/i               , graccaa              ); --->  3
NOTE: Execution succeeded. 18 rows affected.
2752  quit;

1 个答案:

答案 0 :(得分:1)

PRXMATCH可能正在使用隐式/o进行一些奇怪的已编译正则表达式缓存。即使考虑到某些PRXMATCH模式可能已经“一次”编译,我也无法弄清楚观察到的输出背后的原理。

不幸的是,DS2不喜欢CALL PRXDEBUG(1);,它可能会带来一些启发。

来自PRXMATCH docs

  

编译Perl正则表达式
  如果perl-regular-expression是常数或使用/ o选项,则Perl正则表达式将被编译一次,并且每次使用PRXMATCH都会重新使用编译后的表达式。如果perl-regular-expression不是常数,并且不使用/ o选项,则将为每次对PRXMATCH的调用重新编译Perl正则表达式。
  注意:当您在DATA步骤,WHERE子句或PROC SQL中使用PRXMATCH时,就会发生一次编译行为。对于所有其他用途,每次调用PRXMATCH都会重新编译perl-regular-expression。

因此,文档并没有完全阐明DS2中发生的情况,但是您知道有时会发生一些特殊情况。

最好的 fix 是显式PRXPARSE动态正则表达式模式以获得在PRXMATCH中使用的ID

            dcl int rx;
            rx = prxparse(search_term);
            c = prxmatch(rx, search_text);

这可能是内存问题,因为没有PRXFREE函数并且DS2不允许使用调用例程CALL PRXFREE(rx);为避免潜在的“内存”问题,请创建prxparsed ID的数组或哈希将使用的模式,以及使用通过search_term查找获取的ID的模式。