BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Ryanb2
Quartz | Level 8

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();

 

1 ACCEPTED SOLUTION

Accepted Solutions
PGStats
Opal | Level 21

Try using %qscan instead of %scan.

PG

View solution in original post

11 REPLIES 11
PGStats
Opal | Level 21

Try using %qscan instead of %scan.

PG
Ryanb2
Quartz | Level 8
Thanks PGStats! That seems to have done the job. I appreciate your help.
ChrisNZ
Tourmaline | Level 20

This works. Changes highlighted

%let varname= %scan(%bquote(&varlist.), &i., %str( ));  
%let patternM= %qscan(%bquote(&pattern), &i., ~);  

 

Patrick
Opal | Level 21

@Ryanb2

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.

ChrisNZ
Tourmaline | Level 20

Inded @Patrick is right.

 

If you want to "allow letters, spaces, hyphens, commas, and apostrophes" you probably want

 BADFLAG=prxmatch("/[^A-Z ,'-]/i", VAR);

Ryanb2
Quartz | Level 8

You are absolutely right.  I didn't include the ^.  I so focusing on the single quote issue.  Thank you!

s_lassen
Meteorite | Level 14

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.

Patrick
Opal | Level 21

@Ryanb2

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;
Ryanb2
Quartz | Level 8
Thanks Patrick. I'll try this out sometime.
Ryanb2
Quartz | Level 8
This appears to work as well. Thanks for the suggestion!
Ryanb2
Quartz | Level 8

This works too.  Thanks for the suggestion!

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 11 replies
  • 2309 views
  • 7 likes
  • 5 in conversation