SAS BASE method %index where second parametr equals ',' - sas

I have some code:
%if %index(&CompanyName,&) %then %do;
%let error_code = 4;
%let error_msg = &ERR_CONT_SYMB;
%return;
%end;
When a company name has an & symbol, an error should be thrown.
If replaced with another character such as % $ . then everything works the same.
I need to replace the & with a comma, but that's not possible.
No quotes help (, ',' ",")

Related

Reading from _OUTPUT_connect

In SAS DI when I connect a user written transformation to an output table, the variable _OUTPUT_connect is assigned. In my case it looks something like this:
%let _OUTPUT_connect = DEFER=YES READBUFF=25000 DBCLIENT_MAX_BYTES=1 DB_LENGTH_SEMANTICS_BYTE=NO PATH=MY_PATH AUTHDOMAIN="MY_AUTH_DOMAIN"
Now I'm trying to extract the PATH and AUTHDOMAIN variables from _OUTPUT_connect. My solution for now is the following:
%let _authdomain = %sysfunc(scan(&_OUTPUT_connect,7," "));
%let _path = %sysfunc(scan(%sysfunc(scan(&_OUTPUT_connect,5," ")),2,"="));
This works but it breaks if the order of the _OUTPUT_connect variables changes.
I thought I'd use regex to match the paramater values: PATH=[match_this] and AUTHDOMAIN="[match_this]", but I have problems parsing the variable _OUTPUT_connect because it contains double quotes. When I manually assign _OUTPUT_connect without the double quotes I can do the following
data _null_;
re = prxparse('/PATH=(\w)*/');
string = "&_OUTPUT_connect";
position = prxmatch(re, string);
put position=;
matched_pattern=prxposn(re, 0, string);
put matched_pattern=;
run;
Output:
position=75
matched_pattern=PATH=A1091211_SAS_SRV
The problem however is that _OUTPUT_connect contains double quotes, and the regex function fails when the input string contains double quotes. Since _OUTPUT_connect is assigned automatically, I cannot change the format.
I've tried to remove the double quotes from _OUTPUT_connect using this %let unquoted =%sysfunc(translate(%quote(&test),' ','"'));. This does work, but it puts a whitespace in place of the double quotes.
Is there an easy way to retrieve the values of PATH and AUTHDOMAIN from _OUTPUT_connect?
You can extract the name value pairs of the connection string by using SCAN with modifiers.
Example:
data nvps(label='name value pairs' keep=name value);
s = 'name1=value1 name2="value2" name3="value 3"';
do index = 1 to countw(s,' ','q');
nvp = scan(s,index,' ','q');
name = scan(nvp,1,'=','q');
value = scan(nvp,2,'=','q');
output;
end;
run;

SAS Retain not working for 1 string variable

The below code doesn't seem to be working for the variable all_s when there is more than 1 record with the same urn. Var1,2,3 work fine but that one doesn't and I cant figure out why. I am trying to have all_s equal to single_var1,2,3 concatenated with no spaces if it's first.urn but I want it to be
all_s = all_s + ',' + single_var1 + single_var2 + single_var3
when it's not the first instance of that urn.
data dataset_2;
set dataset_1;
by URN;
retain count var1 var2 var3 all_s;
format var1 $40. var2 $40. var3 $40. all_s $50.;
if first.urn then do;
count=0;
var1 = ' ';
var2 = ' ';
var3 = ' ';
all_s = ' ';
end;
var1 = catx(',',var1,single_var1);
var2 = catx(',',var2,single_var2);
var3 = catx(',',var3,single_var3);
all_s = cat(all_s,',',single_var1,single_var2,single_var3);
count = count+1;
if first.urn then do;
all_s = cat(single_var1,single_var2,single_var3);
end;
run;
all_s is not large enough to contain the concatenation if the total length of the var1-var3 values within the group exceeds $50. Such a scenario seems likely with var1-var3 being $40.
I recommend using the length function to specify variable lengths. format will create a variable of a certain length as a side effect.
catx removes blank arguments from the concatenation, so if you want spaces in the concatenation when you have blank single_varN you won't be able to use catx
A requirement that specifies a concatenation such that non-blank values are stripped and blank values are a single blank will likely have to fall back to the old school trim(left(… approach
Sample code
data have;
length group 8 v1-v3 $5;
input group (v1-v3) (&);
datalines;
1 111 222 333
1 . 444 555
1 . . 666
1 . . .
1 777 888 999
2 . . .
2 . b c
2 x . z
run;
data want(keep=group vlist: all_list);
length group 8 vlist1-vlist3 $40 all_list $50;
length comma1-comma3 comma $2;
do until (last.group);
set have;
by group;
vlist1 = trim(vlist1)||trim(comma1)||trim(left(v1));
vlist2 = trim(vlist2)||trim(comma2)||trim(left(v2));
vlist3 = trim(vlist3)||trim(comma3)||trim(left(v3));
comma1 = ifc(missing(v1), ' ,', ',');
comma2 = ifc(missing(v2), ' ,', ',');
comma3 = ifc(missing(v3), ' ,', ',');
all_list =
trim(all_list)
|| trim(comma)
|| trim(left(v1))
|| ','
|| trim(left(v2))
|| ','
|| trim(left(v3))
;
comma = ifc(missing(v3),' ,',',');
end;
run;
Reference
SAS has operators and multiple functions for string concatenation
|| concatenate
cat concatenate
catt concatenate, trimming (remove trailing spaces) of each argument
cats concatenate, stripping (remove leading and trailing spaces) of each argument
catx concatenate, stripping each argument and delimiting
catq concatenate with delimiter and quote arguments containing the delimiter
From SAS 9.2 documentation
Comparisons
The results of the CAT, CATS, CATT, and CATX functions are usually equivalent to results that are produced by certain combinations of the concatenation operator (||) and the TRIM and LEFT functions. However, the default length for the CAT, CATS, CATT, and CATX functions is different from the length that is obtained when you use the concatenation operator. For more information, see Length of Returned Variable.
Note: In the case of variables that have missing values, the concatenation produces different results. See Concatenating Strings That Have Missing Values.
Some example data would be helpful, but I'm going to give it a shot and ask you to try
all_s = cat(strip(All_s),',',single_var1,single_var2,single_var3);

how to avoid spaces in put satement in SAS

I'm trying to write a json file from a data step.
but my put statements always add unwanted spaces after variables.
put ' {"year":' year ',';
will create {"year":2013 ,
and
put ' {"name":"' %trim(name) '", ' ;
will create {"name":"Rubella virus ",
How can I remove the space after "Rubella virus" without overcomplicating things?
My best solution so far is to create a variable that uses cats and then put the newvariable a bit like this:
newvar=cats('{"name":"',name,'",');
put newvar;
Thanks!
You need to move pointer back by one step. You do this by asking to go forward by minus one step. Use this:
put ' {"name":"' name(+)-1 '", ' ;
Weird, I know, but it works.
Here is example with sashelp.class:
Code:
data _null_;
set sashelp.class end = eof;
if _N_ eq 1 then
put '[';
put '{ "Name":"' Name+(-1)
'","Sex":"' Sex+(-1)
'","Age":"' Age+(-1)
'","Height":"' Height+(-1)
'","Weight":"' Weight+(-1)
'"}';
if eof then
put ']';
else put ',';
run;
Result:
[
{ "Name":"Alfred","Sex":"M","Age":"14","Height":"69","Weight":"112.5"}
,
{ "Name":"Alice","Sex":"F","Age":"13","Height":"56.5","Weight":"84"}
,
{ "Name":"Barbara","Sex":"F","Age":"13","Height":"65.3","Weight":"98"}
,
{ "Name":"Carol","Sex":"F","Age":"14","Height":"62.8","Weight":"102.5"}
,
{ "Name":"Henry","Sex":"M","Age":"14","Height":"63.5","Weight":"102.5"}
,
{ "Name":"James","Sex":"M","Age":"12","Height":"57.3","Weight":"83"}
,
{ "Name":"Jane","Sex":"F","Age":"12","Height":"59.8","Weight":"84.5"}
,
{ "Name":"Janet","Sex":"F","Age":"15","Height":"62.5","Weight":"112.5"}
,
{ "Name":"Jeffrey","Sex":"M","Age":"13","Height":"62.5","Weight":"84"}
,
{ "Name":"John","Sex":"M","Age":"12","Height":"59","Weight":"99.5"}
,
{ "Name":"Joyce","Sex":"F","Age":"11","Height":"51.3","Weight":"50.5"}
,
{ "Name":"Judy","Sex":"F","Age":"14","Height":"64.3","Weight":"90"}
,
{ "Name":"Louise","Sex":"F","Age":"12","Height":"56.3","Weight":"77"}
,
{ "Name":"Mary","Sex":"F","Age":"15","Height":"66.5","Weight":"112"}
,
{ "Name":"Philip","Sex":"M","Age":"16","Height":"72","Weight":"150"}
,
{ "Name":"Robert","Sex":"M","Age":"12","Height":"64.8","Weight":"128"}
,
{ "Name":"Ronald","Sex":"M","Age":"15","Height":"67","Weight":"133"}
,
{ "Name":"Thomas","Sex":"M","Age":"11","Height":"57.5","Weight":"85"}
,
{ "Name":"William","Sex":"M","Age":"15","Height":"66.5","Weight":"112"}
]
Regards,
Vasilij
For the character fields you can use the $QUOTE. format to add the quotes. Use the : to remove the trailing blanks in the value of the variable.
put '{ "Name":' Name :$quote.
',"Sex":' Sex :$quote.
',"Age":"' Age +(-1) '"'
',"Height":"' Height +(-1) '"'
',"Weight":"' Weight +(-1) '"'
'}'
;
If you are looking to have 'cleaner' code, you could build yourself a helper function or two using proc fcmp. This function will take a string description, the name of the field you want, and then whether or not to quote the returned string. Note that if your values can contain quotes, you may want to use the quote() function instead of t
Example Function:
proc fcmp outlib=work.funcs.funcs;
function json(iName $, iField $, iQuote) $;
length result $200;
quote_char = ifc(iQuote,'"','');
result = cats('"', iName, '":',quote_char, iField, quote_char );
return (result );
endsub;
run;
Example Usage:
data _null_;
set sashelp.class;
x = catx(',',
json("name",name,1),
json("age",age,0));
put x;
run;
Example Output:
"name":"Alfred","age":14
"name":"Alice","age":13
"name":"Barbara","age":13
"name":"Carol","age":14
"name":"Henry","age":14
"name":"James","age":12
"name":"Jane","age":12

how to pass a string to a macro sas without special char

I wrote this macro in sas to have some information about some files :
%macro info_1(cmd);
filename dirList pipe &cmd.;
data work.dirList;
infile dirList length=reclen;
input file $varying200. reclen;
permission=scan(file,1,"");
if input(scan(file,2,""), 8.)=1;
user=scan(file,3,"");
group=scan(file,4,"");
file_size_KB=round(input(scan(file,5,""), 8.)/1024,1);
file_size_MB=round(input(scan(file,5,""), 8.)/1024/1024,1);
modified_time=input(catx(" ",scan(file,6," "),scan(file,7,"")),anydtdtm.);
date_mod = datepart(modified_time);
time_zone=scan(file,8,"");
file_name=scan(file,-1,"");
format modified_time datetime19.;
format file_size_MB comma9.;
format date_mod date9.;
run;
%mend info_1;
then i declare this macro variable:
%let cmd = ls --full-time;
%let sep1= %quote( );
%let path = /data/projects/flat_file/meteo ;
%let file = *.json ;
%let sep2 = %quote(/) ;
%let fullpath = &cmd.&sep1.&path.&sep2.&file;
Then i try to execute the macro :
%info_1(&fullpath.);
And i see a strange thing. I post a image because it is impossible to describe it. I guess that there are special chars.
How to fix that thing?
Inside your macro I believe you just need to add quotes around this line:
filename dirList pipe &cmd.;
Right now after the macro resolution is happening it is treating it like:
filename dirList pipe ls --full-time;
... which is treating the ls part onwards like parameters to the filename statement. When fixed the code should appear as:
filename dirList pipe "&cmd";
Which will then be resolved as:
filename dirList pipe "ls --full-time";

In SAS, outside of a data step, what is the best way to replace a character in a macro variable with a blank?

In SAS, outside of a data step, what is the best way to replace a character in a macro variable with a blank?
It seems that TRANSLATE would be a good function to use. However when using %SYSFUNC with this function, the parameters are not surrounded with quotes. How do you indicate a blank should be used as replacement?
The %str( ) (with a blank between the parens) can be used to indicate a blank for this parameter. Also be careful with TRANSLATE...the 2nd param is the replacement char...however in TRANWRD it is reversed.
%macro test ;
%let original= translate_this_var ;
%let replaceWithThis= %str( ) ;
%let findThis= _ ;
%let translated= %sysfunc(translate(&original, &replaceWithThis, &findThis)) ;
%put Original: &original ***** TRANSLATEd: &translated ;
%mend ;
%test;
%macro test2 ;
%let original= translate_this_var ;
%let replaceWithThis= %str( ) ;
%let findThis= _ ;
%let tranwrded= %sysfunc(tranwrd(&original, &findThis, &replaceWithThis)) ;
%put Original: &original ***** TRANWRDed: &tranwrded ;
%mend ;
%test2
There are no quotes in macro language. The only quotes characters that are in use are the & , % etc. to indicate that the text should be interpreted as a macro "operator". A blank is represented by %str( ) as indicated above in Carolina's post.
you can use perl reg ex instead, like:
%put ***%sysfunc(prxchange(s/x/ /, -1, abxcdxxf))***;
/* on log
***ab cd f***
*/