在SAS中动态连接变量
Concatenating a variable dynamically in SAS
我想创建一个变量来解析字符串中指定字符 (*
) 之前的字符。但是我现在问自己,如果这个指定的字符在一个字符串中出现多次(如下例所示),如何检索一个变量,该变量连接之前出现的所有字符,用逗号分隔?
示例:
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
;
run;
代码:
data want;
set have;
cnt = count(string, "*");
_startpos = 0;
do i=0 to cnt until(_startpos=0);
before = catx(",",substr(string, find(string, "*", _startpos+1)-1,1));
end;
drop i _startpos;
run;
第一次和第二次观察的代码输出 before=C
。但是,我希望第一个观察结果为 before=C,E
,第二次观察结果为 before=C,W,d
。
确保递增 _STARTPOS 以便您的循环结束。您可以使用 CATX() 添加逗号。使用 CHAR() 而不是 SUBSTR() 来简化选择字符。还要确保告诉数据步骤如何定义新变量,而不是强迫它猜测。我还包括测试来处理 *
处于第一个位置的情况。
data have;
input string .;
datalines;
ABC*EDE*
EFCC*W*d*
*XXXX*
asdf
;
data want;
set have;
length before ;
_startpos = 0;
do cnt=0 to length(string) until(_startpos=0);
_startpos = find(string,'*',_startpos+1);
if _startpos>1 then before = catx(',',before,char(string,_startpos-1));
end;
cnt=cnt-(string=:'*');
drop i _startpos;
run;
结果:
Obs string before cnt
1 ABC*EDE* C,E 2
2 EFCC*W*d* C,W,d 3
3 *XXXX* X 1
4 asdf 0
您可以使用 Perl 正则表达式替换模式来转换原始字符串。
示例:
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
;
data want;
set have;
csl = prxchange('s/([^*]*?)([^*])\*/,/',-1,string); /* comma separated letters */
csl = prxchange('s/, *$//',1,csl); /* remove trailing comma */
run;
call scan
也是获得每个 *
.
位置的好选择
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
****
asdf
;
data want;
length before .;
set have;
do i = 1 to count(string,'*');
call scan(string,i,pos,len,'*');
before = catx(',',before,substrn(string,pos+len-1,1));
end;
put _n_ = +7 before=;
run;
结果:
_N_=1 before=C,E
_N_=2 before=C,W,d
_N_=3 before=
_N_=4 before=
我想创建一个变量来解析字符串中指定字符 (*
) 之前的字符。但是我现在问自己,如果这个指定的字符在一个字符串中出现多次(如下例所示),如何检索一个变量,该变量连接之前出现的所有字符,用逗号分隔?
示例:
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
;
run;
代码:
data want;
set have;
cnt = count(string, "*");
_startpos = 0;
do i=0 to cnt until(_startpos=0);
before = catx(",",substr(string, find(string, "*", _startpos+1)-1,1));
end;
drop i _startpos;
run;
第一次和第二次观察的代码输出 before=C
。但是,我希望第一个观察结果为 before=C,E
,第二次观察结果为 before=C,W,d
。
确保递增 _STARTPOS 以便您的循环结束。您可以使用 CATX() 添加逗号。使用 CHAR() 而不是 SUBSTR() 来简化选择字符。还要确保告诉数据步骤如何定义新变量,而不是强迫它猜测。我还包括测试来处理 *
处于第一个位置的情况。
data have;
input string .;
datalines;
ABC*EDE*
EFCC*W*d*
*XXXX*
asdf
;
data want;
set have;
length before ;
_startpos = 0;
do cnt=0 to length(string) until(_startpos=0);
_startpos = find(string,'*',_startpos+1);
if _startpos>1 then before = catx(',',before,char(string,_startpos-1));
end;
cnt=cnt-(string=:'*');
drop i _startpos;
run;
结果:
Obs string before cnt
1 ABC*EDE* C,E 2
2 EFCC*W*d* C,W,d 3
3 *XXXX* X 1
4 asdf 0
您可以使用 Perl 正则表达式替换模式来转换原始字符串。
示例:
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
;
data want;
set have;
csl = prxchange('s/([^*]*?)([^*])\*/,/',-1,string); /* comma separated letters */
csl = prxchange('s/, *$//',1,csl); /* remove trailing comma */
run;
call scan
也是获得每个 *
.
data have;
infile datalines delimiter=",";
input string :.;
datalines;
ABC*EDE*,
EFCC*W*d*
****
asdf
;
data want;
length before .;
set have;
do i = 1 to count(string,'*');
call scan(string,i,pos,len,'*');
before = catx(',',before,substrn(string,pos+len-1,1));
end;
put _n_ = +7 before=;
run;
结果:
_N_=1 before=C,E
_N_=2 before=C,W,d
_N_=3 before=
_N_=4 before=