去除问卷含特殊字符的重复答案及SAS宏报错问题求助
解决SAS宏处理多选问卷答案时的函数解析错误问题
我来帮你梳理下问题根源和解决方案:
为什么会报错?
你看到的ERROR: The function NO is unknown,是因为你的答案里有NO (go to the 9th question)这种带括号的内容。SAS宏处理器在解析宏变量时,会把NO (识别为试图调用名为NO的函数(因为括号是宏函数的语法标识),但实际上这只是答案文本的一部分,所以触发了错误。
原宏里用%scan在宏循环中直接处理带特殊字符的字符串,很容易触发这类宏解析的意外行为——毕竟宏语言是预编译解析的,对括号、空格、逗号这类特殊字符的处理和数据步的字符串处理逻辑完全不同。
更稳健的解决方案:用数据步拆分答案
相比在宏循环里折腾字符串,用数据步来拆分逗号分隔的答案会可靠得多,因为数据步是在执行阶段处理数据行的字符串,不会误解析特殊字符。这里给你重新写一个宏:
%macro coll_ans(lib, tab); /* 一次性声明所有要生成的全局宏变量 */ %global betav1-betav&n_que.; %do _i_ = 1 %to &n_que.; /* 第一步:拆分当前问题的所有多选答案,生成临时数据集 */ data temp_split&_i_.; set &lib..&tab.; /* 过滤空答案 */ where v&_i_. ne ' '; /* 根据你的答案长度调整text的长度 */ length text $200; /* 拆分逗号分隔的字符串,'mq'修饰符确保引号内的逗号不会被拆分(如果有这类场景) */ do _j_ = 1 to countw(v&_i_., ',', 'mq'); text = scan(v&_i_., _j_, ',', 'mq'); /* 去掉答案前后的空格(比如用户选的"a, b"会拆成"a"和" b",strip后变成"b") */ text = strip(text); output; end; run; /* 第二步:去重后生成对应的宏变量 */ proc sql noprint; select distinct text into :betav&_i_. separated by ', ' from temp_split&_i_.; quit; /* 清理临时数据集(可选,避免占内存) */ proc datasets nolist noprint; delete temp_split&_i_.; run; %end; %mend coll_ans;
这个宏的优势:
- 用数据步的
scan和countw处理字符串,完全避免宏解析特殊字符的问题,不管答案里有括号、空格还是其他符号都能正确拆分。 strip函数自动清理答案前后的空格,避免因为用户输入或问卷导出的空格导致重复统计(比如"NO"和" NO"会被当成不同答案)。- 一次性声明全局宏变量,代码更整洁。
如果一定要用原宏的思路修正
如果你想基于原来的宏修改,需要用%superq完全保护宏变量的内容,避免宏解析特殊字符,同时给%scan加上修饰符:
把原宏里的%do _j_循环部分改成:
%do _j_ = 1 to %sysfunc(countw(%superq(betav&_i_.), ',', 'mq')) %by 1; text = "%scan(%superq(betav&_i_.), &_j_., ',', 'mq')"; output; %end;
不过这种方法还是不如数据步稳健,因为如果答案里包含双引号,会触发新的语法错误,所以更推荐前面的数据步方案。
测试建议
你可以先单独测试一个问题(比如把%do _i_ = 1 to &n_que.改成%do _i_ = 1 to 1),查看生成的temp_split1数据集和betav1宏变量是否正确,确认没问题后再批量处理所有问题。
内容的提问来源于stack exchange,提问作者mrtovsky
相关产品推荐
相关产品推荐

