Are there alternatives to negative lookbehind regular expressions with variable lengths?
Do not match if "no" or "negative" are before certain key words (infarct)|(MI)|(myocardial infarction).
SAS returns the following error: Variable length lookbehind not implemented before HERE mark in regex
Thanks.
data text;
input string $60.;
cards;
Acute infarct.
Acute MI.
Acute myocardial infarction.
Extensive infarct found in the.
Massive infarct found in the.
No infarct.
Negative infarct.
Negative for infarct.
No CT evidence of infarct.
No apparent evidence of infarct.
No apparent CT evidence of infarct.
No evidence of infarct.
No evidence of infarct.
Evidence of infarct.
Evidence for infarct.
;
/* Only Match:
Acute infarct
Acute MI
Acute myocardial infarction
Extensive infarct found in the
Massive infarct found in the
evidence of infarct
evidence for infarct
*/
data text_prx;
set text;
if _n_=1 then do;
retain re;
re = prxparse('/(?<!\bno\b.{0,225}|\bnegative\b.{0,225})((infarct)|(MI)|(myocardial infarction))/i');
putlog 'ERROR: regex is malformed';
stop;
end;
end;
if prxmatch(re,string) then infarct=1;
else infarct=0;
run;
proc print data=text_prx(drop=re);
run;
Hello @PharmlyDoc,
How about searching for the positive and negative words separately and then comparing character positions?
data text_prx(drop=re_: pos_:);
set text;
if _n_=1 then do;
re_i + prxparse('/(infarct)|(\bMI\b)|(myocardial infarction)/i');
re_n + prxparse('/\bno\b|\bnegative\b/i');
end;
pos_i = prxmatch(re_i,string);
pos_n = prxmatch(re_n,string);
infarct = pos_i & not (0<pos_n<pos_i);
run;
(Of course, "infarct" is a substring of "myocardial infarction", but I assume that you may want to evaluate the matches, e.g., with PRXPOSN.)
Hello @PharmlyDoc,
How about searching for the positive and negative words separately and then comparing character positions?
data text_prx(drop=re_: pos_:);
set text;
if _n_=1 then do;
re_i + prxparse('/(infarct)|(\bMI\b)|(myocardial infarction)/i');
re_n + prxparse('/\bno\b|\bnegative\b/i');
end;
pos_i = prxmatch(re_i,string);
pos_n = prxmatch(re_n,string);
infarct = pos_i & not (0<pos_n<pos_i);
run;
(Of course, "infarct" is a substring of "myocardial infarction", but I assume that you may want to evaluate the matches, e.g., with PRXPOSN.)
Note, if you need to know which of many possible substrings was matched, (using PRXPOSN) you should list the longer substrings first
if _n_=1 then do;
re_i + prxparse('/\b(myocardial infarction|infarct|MI)\b/i');
re_n + prxparse('/\bno\b|\bnegative\b/i');
end;
pos_i = prxmatch(re_i,string);
pos_n = prxmatch(re_n,string);
infarct = pos_i & not (0<pos_n<pos_i);
if infarct then word = prxposn(re_i, 1, string);
Thanks, @PGStats, for chiming in. I was under the impression that "myocardial infarction" is matched first in strings like "Acute myocardial infarction" even if listed after "infarct" in the regular expression because it starts earlier in the string. However, if the regex was /(infarction|infarct)/i, then the order of the two words would make a difference for PRXPOSN. (My guess that PRXPOSN might be involved somewhere else in the OP's code was just based on the way the regex was written.)
Thanks for helping with this.
Why use
re_i + prxparse('/ /');
instead of
re_i = prxparse('/ /');
?
I would still use your method even if SAS provided a flavor of regex that allows for variable length negative lookbehind. This is an excellent workaround!!
Yes, I've found the prxposn function helpful for seeing what is being captured/matched.
You're welcome.
@PharmlyDoc wrote:
Why use
re_i + prxparse('/ /');
instead of
re_i = prxparse('/ /');
?
Just to save the RETAIN statement. The sum statement implies RETAIN and the result in re_i and re_n, respectively, is the same as with an assignment statement. (I learned this application of the sum statement to regex definitions from PGStats, years ago.)
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.