Got it. The trick was when adding quotes, to make sure they weren't adjacent to the word boundaries by inserting a space. So initially the string is padded with additional spaces. Then right at the end, I remove the additional spaces with compress()
. That way we can sneak past the test for quoted string identifiers!
%let x = A B C ;
%let y = %sysfunc(compress(%str(%' )%sysfunc(tranwrd(%sysfunc(compbl(&x)), %str( ), %str( %',%' ) ))%str( %') ));
%put &y;
Result:
'A','B','C'
Kinda ugly though.
EDIT: 2nd Attempt:
Thought I'd cheat and use proc fcmp
. End result is much nicer:
proc fcmp outlib=common.funcs.funcs;
function delimit_words(iString $) $;
result = "'" || tranwrd(cats(compbl(iString))," ", "','") || "'";
return (result );
endsub;
run;
Datastep example:
data x;
x = " A B C ";
y = delimit_words(x);
put y=;
run;
Improved macro example:
%let x = A B C ;
%let y = %sysfunc(delimit_words(&x));
%put &y;
For some reason proc fcmp
was giving me unexpected results if I tried to use the cats()
function instead of the ||
concatenators so I just went with ||
. The function could be improved by allowing the user to specify what symbol(s) constitute a word boundary, as well as whether or not to quote the output, and if so, whether to use single or double quotes... but I'll add those in on an as-needed basis.