将 prxmatch 与 DS2 一起使用时出现 SAS 错误

SAS error using prxmatch with DS2

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

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

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 5ITEM 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;

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

不幸的是,DS2 不喜欢 CALL PRXDEBUG(1); 这可能已经说明了一些问题。

来自PRXMATCH docs

Compiling a Perl Regular Expression
If perl-regular-expression is a constant or if it uses the /o option, then the Perl regular expression is compiled once and each use of PRXMATCH reuses the compiled expression. If perl-regular-expression is not a constant and if it does not use the /o option, then the Perl regular expression is recompiled for each call to PRXMATCH.
Note: The compile-once behavior occurs when you use PRXMATCH in a DATA step, in a WHERE clause, or in PROC SQL. For all other uses, the perl-regular-expression is recompiled for each call to PRXMATCH.

所以文档并没有完全说明 DS2 中发生了什么,但你知道有时会发生一些特别的事情。

最好的修复 是明确地 PRXPARSE 动态正则表达式模式以获得在 PRXMATCH

中使用的 id
            dcl int rx;
            rx = prxparse(search_term);
            c = prxmatch(rx, search_text);

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