Hi there - first time posting. Hoping you can help me!
I have created a program that prompts for a password. I need to identify if the password contains any double quotes ("), matched or unmatched. Whether that be removing them and comparing a before and after length or finding the location of the " and if the result is >0 then it one exists. The catch is I also need to ensure that any predefined SAS macro variables that could inadvertently end up in the password do not resolve. Here are a couple of things I have tried:
Password Entered: Abc"2025&sysdate
OPTIONS MPRINT SYMBOLGEN;
*Entered into Prompt;
*_NOLOG_pw = Abc"2024&sysdate;
%PUT _NOLOG_pw = &_NOLOG_PW;
%LET NOLOG = %SUPERQ(_NOLOG_PW);
%PUT NOLOG - &NOLOG.;
%LET NOLOG_NRSTR = %NRSTR(&NOLOG);
%PUT NOLOG_NRSTR = &NOLOG_NRSTR;
%let nolog_find = %sysfunc(find(&NOLOG_NRSTR, %str(%"))); *Resolves to 0;
%put &nolog_find;
data _null_;
TRANWORD = translate(&NOLOG,%str( ),%str(%")); * Results in error;
call symput('NOLOG_TRANWORD',TRANWORD);
RUN;
%PUT NOLOG_TRANWORD = &NOLOG_TRANWORD;
Here is the log:
Any help you can provide will be greatly appreciated.
Thanks!
I suspect you are having trouble because you are using %SYSFUNC() to call SAS functions. That causes trouble with strings that have macro triggers as %SYSFUNC() has to convert the macro strings to actual strings to pass to the SAS functions.
But from your description there SAS macro already has a function for this, %INDEX(). So there is no need to get %SYSFUNC() involved and so no need to worry about how it handles macro triggers like & and %.
First let's make a macro variable with that string. Easier way is using a DATA step.
data _null_;
call symputx('_NOLOG_pw', 'Abc"2024&sysdate');
run;
Now we can find the location of the first " character like this:
%let location = %index(%superq(_nolog_pw),%str(%"));
But what is the goal here? Is the goal to convert the macro variable into something that you can use more easily? Since everywhere you need to reference a password you can normally use single quotes around the value (like in my data step above) then just add the single quotes to the macro variable. That can easily be done with a data step. Use SYMGET() to retrieve the value without worrying about macro quoting. Use QUOTE() to add the quotes. Use CALL SYMPUTX() to store the result back into a macro variable. Perhaps the same one?
1 data _null_; 2 call symputx('_NOLOG_pw', 'Abc"2024&sysdate'); 3 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 4 5 data _null_; 6 call symputx('_NOLOG_pw',quote(symget('_NOLOG_PW'),"'")); 7 run; NOTE: DATA statement used (Total process time): real time 0.01 seconds cpu time 0.01 seconds 8 9 %put &=_nolog_pw; _NOLOG_PW='Abc"2024&sysdate'
Do you want the &SYSDATE to evaluate? If so then use %BQUOTE() to handle the potentially unbalanced quotes.
1 data _null_; 2 call symputx('_NOLOG_pw', 'Abc"2024&sysdate'); 3 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 4 5 %put Raw value is |%superq(_nolog_pw)|; Raw value is |Abc"2024&sysdate| 6 %put Value after evaluation is |%bquote(&_nolog_pw)|; Value after evaluation is |Abc"202423DEC24|
%let _NOLOG_pw =%bquote( Abc"2024&sysdate ); /* %let _NOLOG_pw =%bquote( &_NOLOG_pw ); */
%PUT _NOLOG_pw = &_NOLOG_PW ;
%let nolog_find = %sysfunc(find(&_NOLOG_pw, %str(%")));
%put &=nolog_find;
1 %let _NOLOG_pw =%bquote( Abc"2024&sysdate ); /* %let _NOLOG_pw =%bquote( &_NOLOG_pw ); */ 2 %PUT _NOLOG_pw = &_NOLOG_PW ; _NOLOG_pw = Abc"202422DEC24 3 4 5 6 7 %let nolog_find = %sysfunc(find(&_NOLOG_pw, %str(%"))); 8 %put &=nolog_find; NOLOG_FIND=5
@Ksharp wrote:
%let _NOLOG_pw =%bquote( Abc"2024&sysdate ); /* %let _NOLOG_pw =%bquote( &_NOLOG_pw ); */ %PUT _NOLOG_pw = &_NOLOG_PW ; %let nolog_find = %sysfunc(find(&_NOLOG_pw, %str(%"))); %put &=nolog_find;
1 %let _NOLOG_pw =%bquote( Abc"2024&sysdate ); /* %let _NOLOG_pw =%bquote( &_NOLOG_pw ); */ 2 %PUT _NOLOG_pw = &_NOLOG_PW ; _NOLOG_pw = Abc"202422DEC24 3 4 5 6 7 %let nolog_find = %sysfunc(find(&_NOLOG_pw, %str(%"))); 8 %put &=nolog_find; NOLOG_FIND=5
Two issues.
First the double quote is the fourth character, not the the fifth. You added spaces before and after the value in your %BQUOTE() call so your answer is off by 1.
Second why use FIND? INDEX works fine for this problem. And SAS macro has a built in %INDEX() function that can be used.
I suspect you are having trouble because you are using %SYSFUNC() to call SAS functions. That causes trouble with strings that have macro triggers as %SYSFUNC() has to convert the macro strings to actual strings to pass to the SAS functions.
But from your description there SAS macro already has a function for this, %INDEX(). So there is no need to get %SYSFUNC() involved and so no need to worry about how it handles macro triggers like & and %.
First let's make a macro variable with that string. Easier way is using a DATA step.
data _null_;
call symputx('_NOLOG_pw', 'Abc"2024&sysdate');
run;
Now we can find the location of the first " character like this:
%let location = %index(%superq(_nolog_pw),%str(%"));
But what is the goal here? Is the goal to convert the macro variable into something that you can use more easily? Since everywhere you need to reference a password you can normally use single quotes around the value (like in my data step above) then just add the single quotes to the macro variable. That can easily be done with a data step. Use SYMGET() to retrieve the value without worrying about macro quoting. Use QUOTE() to add the quotes. Use CALL SYMPUTX() to store the result back into a macro variable. Perhaps the same one?
1 data _null_; 2 call symputx('_NOLOG_pw', 'Abc"2024&sysdate'); 3 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 4 5 data _null_; 6 call symputx('_NOLOG_pw',quote(symget('_NOLOG_PW'),"'")); 7 run; NOTE: DATA statement used (Total process time): real time 0.01 seconds cpu time 0.01 seconds 8 9 %put &=_nolog_pw; _NOLOG_PW='Abc"2024&sysdate'
Do you want the &SYSDATE to evaluate? If so then use %BQUOTE() to handle the potentially unbalanced quotes.
1 data _null_; 2 call symputx('_NOLOG_pw', 'Abc"2024&sysdate'); 3 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 4 5 %put Raw value is |%superq(_nolog_pw)|; Raw value is |Abc"2024&sysdate| 6 %put Value after evaluation is |%bquote(&_nolog_pw)|; Value after evaluation is |Abc"202423DEC24|
Thank you for your quick response Tom. The goal is to keep the users password in tact, meaning to not resolve &sysdate. I used that as an example of a possible issue since users should be able to use a '&' in their password. The %index worked perfectly. Thank you so much. The first screenshot below is what comes through from the prompt, and the second screenshot is the log for the %index.
In that case I recommend adding the quotes so you can use the password more easily in code.
Say your user prompt create the macro variable PASSWORD. Your program can then use this data step to generate a single quoted string with the password into either the name macro variable (or a different one if you want).
data _null_;
call symputx('password',quote(symget('password'),"'"));
run;
Now the rest of your code can use the macro variable to pass the password to the places where it is needed. For example in making a database connection:
libname myora oracle path=myserver user=&userid pass=&password ;
how about this way:
*Entered into Prompt;
data _null_;
call symputx('_NOLOG_PW','Abc"2024&sysdate');
run;
/*_NOLOG_pw = Abc"2024&sysdate;*/
/* CODE */
%put %sysfunc(dosubl(%str(
data _null_;
x = resolve(symget('_NOLOG_PW'));
put x=;
call symputx('_NOLOG_PW', x,'G');
call symputx('_location', find(x,'"'),'G');
run;
)));
%PUT _NOLOG_pw = %superq(_NOLOG_PW);
%put &=_location.;
Bart
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.