- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I created a data dictionary with a column for field name and another column with the expected pattern (PRX) for each field. For example, the name fields allow letters, spaces, hyphens, commas, and apostrophes; so the pattern listed for those fields is /[A-Z\-\,\' ]/
I import the data dictionary then create macro variables to hold a listing of field names separated by space, and patterns separated by ~. However, when the code iterates through the patterns it chokes on the single quote. I've tried to put double quotes around the patterns in the data dictionary, and I tried putting ""&doubleQuotes"" around the macro variable, and tried %bquote, but I can't seem to find a combination that works. The SAS code and error message can be found below. The error message below corresponds to pattern /[A-Z\-\,\' ]/
ERROR: Closing delimiter "/" not found after regular expression "/[A-Z\-\,\".
ERROR: The regular expression passed to the function PRXMATCH contains a syntax error.
NOTE: Argument 1 to function PRXMATCH('/[A-Z\-\,\','L''ittle '[12 of 60 characters shown]) at
line 13 column 42 is invalid.
Any advice is appreciated.
Thanks,
Ryan
proc sql noprint;
select VARNAME, PATTERN
into :varlist separated by ' ',
:pattern separated by '~'
from Ccbf_dd
where PATTERN ne '';
quit;
%let cntlist = &sqlobs;
%put &varlist;
%macro test(); %put %bquote(&pattern); %mend test; %test;
%macro Val_check();
data QC_CCBF_values;
set CCBF;
length Issue_desc $250;
Issue_desc=''; /* Initialize Issue_desc */
%do i = 1 %to &cntlist; /* iterate through the list of fields */
%let varname= %scan(%bquote(&varlist.), &i., %str(' ')); /* scans through the list of fields and assigns them one by one to the &varname macro var */
%let patternM= %scan(%bquote(&pattern.), &i., %str('~')); /* scans through the list of patterns and assigns them one by one to the &patternM macro var */
if &varname ne '' and prxmatch("&patternM",&varname.) eq 0 then Issue_desc=catx('; ',Issue_desc,"&varname");
%end;
run;
%mend Val_check;
%Val_check();
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Try using %qscan instead of %scan.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
This works. Changes highlighted
%let varname= %scan(%bquote(&varlist.), &i., %str( )); %let patternM= %qscan(%bquote(&pattern), &i., ~);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Besides of the challenge with the single quote I believe that your current logic won't return the result you're after. The RegEx as per your code will only return something as invalid (value of zero) if ALL characters in the string are invalid.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Inded @Patrick is right.
If you want to "allow letters, spaces, hyphens, commas, and apostrophes" you probably want
BADFLAG=prxmatch("/[^A-Z ,'-]/i", VAR);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
You are absolutely right. I didn't include the ^. I so focusing on the single quote issue. Thank you!
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Rather than messing round with tons of Klingon syntax (macro quoting), why not just single-quote the patterns from the start:
proc sql noprint;
select VARNAME, quote(trim(PATTERN),"'")
into :varlist separated by ' ',
:pattern separated by '~'
from Ccbf_dd
where PATTERN ne '';
quit;
You can then change your PRXMATCH call to PRXMATCH(&PatternM,&Varname), and drop all the macro quoting. And you will not have to worry about patterns containing your string delimiter ("~", in this case), just use %sysfunc(Scan(&pattern,&i,~,Q)), instead of %SCAN or %QSCAN, then delimiters in patterns will not matter.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
This is for me one of these use cases where generating and including code is much easier to implement and debug than using macro code. People are of course different - but that's how my brain works.
Below some code which illustrates the approach.
data parameterTable;
varname='varA'; pattern="/[^A-Z ,'-]/oi"; output;
varname='VarB'; pattern="/[^xyz]/oi"; ;output;
stop;
run;
filename codegen temp;
data _null_;
/* file print;*/
file codegen;
set parameterTable;
put @2 'if ' varname 'ne " " and prxmatch("' pattern +(-1)'",strip(' varname +(-1)')) > 0';
put @4 'then Issue_desc=catx("; ",Issue_desc,"' varname +(-1)'");';
run;
data CCBF;
varA='abc'; varB='xyz';output;
varA='a1b'; varB='xyz';output;
varA='abc'; varB='xbz';output;
varA='a1b'; varB='xbz';output;
stop;
run;
data QC_CCBF_values;
set CCBF;
length Issue_desc $250;
Issue_desc='';
%include codegen / source2;
run;
Besides of easily writing the generated code to the output window (file print) during development, I also like that it's easy to read in the SAS log when executed.
52 data QC_CCBF_values; 53 set CCBF; 54 length Issue_desc $250; 55 Issue_desc=''; 56 %include codegen / source2; NOTE: %INCLUDE (level 1) file CODEGEN is file C:\Users\ssapam\AppData\Local\Temp\SEG8912\SAS Temporary Files\_TD9428_SSAPAM_\#LN00019. 57 + if varA ne " " and prxmatch("/[^A-Z ,'-]/oi",strip(varA)) > 0 58 + then Issue_desc=catx("; ",Issue_desc,"varA"); 59 + if VarB ne " " and prxmatch("/[^xyz]/oi",strip(VarB)) > 0 60 + then Issue_desc=catx("; ",Issue_desc,"VarB"); NOTE: %INCLUDE (level 1) ending. 61 run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
This works too. Thanks for the suggestion!