Unmatched quotation mark issue in SAS - sas

As is known to all, SAS needs special care to quotation marks inside a sentence.
E.g.
%let quoted="I'd like to";
data temp;
set temp;
quoted="&quoted";
run;
error is encounterred when submitting.
In fact I need to copy data to one dataset from another one, in which there are a lot of records containing quotation marks. When assigning, error occurrs and data step stop executing, causing rest of the code to be invalid. So in this case, it's impossible to modify original data set by adding duplicated quotation marks, which doesn't make sense.
So instead of having to add a duplicated one, like, "I''d like to", is there any other way of avoiding the error, or making data step keeping executing?
Thanks,

When using the macro language (including the %let command) you do not want to use quotes to identify text strings. To place a single quote in a string you must use one of the macro utility masking functions such as %str(). The correct syntax to place a single unmatched quote in a macro variable using %let is shown below. The % symbol before the single quote is an escape character to tell SAS that the following character (a single quote) should be used as a literal. Also note that I've removed the double quotes from the %let as they are not required.
%let quoted=%str(I%'d like to);
data temp;
quoted="&quoted";
run;
Cheers
Rob

I'm not sure what you're trying to achieve in the actual situation, but in the above situation it can be solved removing the double quotation marks in the data step.
%let quoted="I'd like to";
data temp;
set temp;
quoted=&quoted;
run;

Related

Rename SAS variables containing special characters

After I imported a huge Excel file containing thousands of data into the SAS, I found some variables showing names with special characters. For example, I have variable names like "pre.tal" and "miss.auto.t0". SAS doesn't allow me to proceed with the statistical analysis due to the special characters in these variable names. I tried the following codes but failed to work. Any ideas? Thanks
options validvarname=any;
data one;
set one;
rename pre.tal_month_t0 = 'prenatal_month_t0'n;
run;
It is the name with special characters that needs quotes and an "n":
rename 'pre.tal_month_t0'n = prenatal_month_t0;
And by the way, if you want to see your original names in listings, you can assign a label to variables
data one;
set one;
rename 'pre.tal_month_t0'n = prenatal_month_t0;`
label prenatal_month_t0 = 'pre.tal_month_t0';
proc print data=one labels;
run;
If you are pressed for time, change the option to validvarname=v7. SAS will automatically make variable names with letters and numbers while replacing special characters and whitespace with underscores. Then you don't have to worry about using name literals ('...'n).
Using options validvarnames=v7; which will allows to use

How to Handle Strings in SAS

Why is it that sometimes we need to wrap the string value in single quotes, sometimes double quotes, sometimes no quotes? This is extremely frustrating when I have to go from one proc to another, especially if it involves changing a file name or url dynamically. What is the logic behind this hideous monstrosity?
%let Name01 = John Smith;
%let Name02 = 'John Smith';
%let Name03 = "John Smith";
All three work.
%let Folder = /97network/read/Regions/Northeast/;
%let FileName = SalesTarget.xlsx;
proc import
datafile = "&Folder.&FileName."
dbms = xlsx
out = SymList replace;
sheet="Sheet1";
run;
Here, &Folder.&FileName. must be in double quotes.
filename OutFile "/06specialty/ATam/AMZN.csv";
proc http url = &urlAddress. method = "get" out = OutFile;
run;
Finally, if I want to download stock prices from Yahoo Finance, url = may take the address in single quotes, or &urlAddress. in no quotes, but you cannot use double quotes. OutFile can be in single or double quotes, but not no quotes. Then in the out = clause, you have OutFile, not &OutFile.
SAS strings are very simple. They are enclosed in either single or double quote characters.
'Hello there'
"Good-bye"
If the enclosing character appears in the string it needs to be doubled up.
'I don''t know'
To your first example it is probably your operating system that is allowing filenames to include optional quotes. On Windows and Linux the qutoes can even be required in some situations when the path includes spaces or other characters that the command shell would normally interpret as delimiters in the command line.
Adding macro logic into the program is probably a large part of your confusion. First figure out what code works for the commands you are using and then you can try to generate that code using the macro processor.
Once you introduce macro logic you need to pay attention to whether your strings are using single or double quotes. There is big difference between how macro logic interacts with single and double quote characters. Strings that are bounded by single quote characters are ignored by the macro processors. So the macro trigger characters & and % are treated as normal characters. But strings that are bounded by double quote characters will be processed.
Your second example adds the complexity of working with URL syntax. URL strings use the & character for its own purpose so you need to take care to understand how SAS is going to see the code you type and whether or not the macro processor will attempt to interpret it to insure the desired string needed for the URL will be created.
SAS has 50 years of history and a lot of the code is legacy. SAS is backwards compatible. You can still run code 30 years old with no issues. There are lots of oddities, such as quotes, that are there...and will always be there. SAS is kind of a conglomeration of ~300 languages (every proc is unique plus multiple meta-languages).
Since SAS will never change, best to just ignore the oddities.
One other thing. SAS runs on lots of O/Ss so every nuance there has to be accommodated in a mostly neutral way.

Find current value of ODS ESCAPECHAR

I am writing a macro to help create documentation which must use ods escapechar. I need it to preserve whatever options/setting the original program used. However, setting a new escape character in the macro overwrites the original program's escape character. How can I change the escape character only for the duration of my macro?
Is there a table somewhere in SAS which stores the current ods escapechar? My thought is to assign the current value to a macro variable and use that to reassign it once my process is complete.
Use the escape sequence instead
(*ESC*)
Then you don't have to know or reset anything.
Somewhere around 9.3 (?) they added &SYSODSescapeChar:
%put &=SYSODSescapeChar ;
SYSODSESCAPECHAR=^
But since the generic (*ESC*) mentioned by data_null_ came first, I'm in the habit of using that, rather than do the save option / reset option / restore saved option dance.

SAS ODS escape character macro variable error

The SAS v9.4 documentation lists an automatic macro variable &sysodsescapechar which contains the current ODS escape character, assigned using ods escapechar=.
Whenever I try to view the macro variable using a %put statement, I get the following error:
ERROR: Open code statement recursion detected.
This happens when open code erroneously causes a macro statement to call another macro statement.
I've tried all of the following:
%put &=sysodsescapechar.;
%put %nrbquote(&sysodsescapechar.);
%put %superq(sysodsescapechar);
They all result in the same error.
When I try to view the macro variable using a data step, it appears to be empty.
data test;
esc = "&sysodsescapechar.";
put esc=;
run;
If the macro variable actually is empty, why do I get open code statement recursion errors? The %put statement on its own is valid, so putting an empty variable shouldn't be an issue.
Any guidance here would be much appreciated.
What's happening is the escape char seems to need a close parentheses. For example:
%put %superq(SYSODSESCAPECHAR););
;
It escapes the ) , which means now you have
%put superq(;);
In your first example, it's a little trickier because a semicolon by itself doesn't seem to be escaped so you have to provide a close parentheses:
%put &SYSODSESCAPECHAR.)x;
x
That works, for example. I'm not sure if it's only close paren or other things that would also allow it to stop trying to escape, but that's the only thing I can tell works.
You can look at the actual value of the macro variable in SASHELP.VMACRO; it's not ' ' (which is indeed what gets passed to the data step even with SYMGET, but it's clearly parsed). In that table it is '03'x, which looks like a uppercase L in the upper half of the character. That is the "End of Text" control character. I suspect the behavior in the editor when using this in text (in a macro variable) is simply a behavior of the editor - '03'x is not representable on many editors (if I try to paste it here, for example, it isn't displayed, but does exist as something I can backspace over with zero width). SAS is clearly capable of dealing with a 'normal' ods escapechar but isn't capable of dealing with '03'x in the same fashion.

SAS: Where statement not working with string value

I'm trying to use PROC FREQ on a subset of my data called dataname. I would like it to include all rows where varname doesn't equal "A.Never Used". I have the following code:
proc freq data=dataname(where=(varname NE 'A.Never Used'));
run;
I thought there might be a problem with trailing or leading blanks so I also tried:
proc freq data=dataname(where=(strip(varname) NE 'A.Never Used'));
run;
My guess is for some reason my string values are not "A.Never Used" but whenever I print the data this is the value I see.
This is a common issue in dealing with string data (and a good reason not to!). You should consider the source of your data - did it come from web forms? Then it probably contains nonbreaking spaces ('A0'x) instead of regular spaces ('20'x). Did it come from a unicode environment (say, Japanese characters are legal)? Then you may have transcoding issues.
A few options that work for a large majority of these problems:
Compress out everything but alphabet characters. where=(compress(varname,,'ka') ne 'ANeverUsed') for example. 'ka' means 'keep only' and 'alphabet characters'.
UPCASE or LOWCASE to ensure you're not running into case issues.
Use put varname HEX.; in a data step to look at the underlying characters. Each two hex characters is one alphabet character. 20 is space (which strip would remove). Sort by varname before doing this so that you can easily see the rows that you think should have this value next to each other - what is the difference? Probably some special character, or multibyte characters, or who knows what, but it should be apparent here.