使用正则表达式将字符串拆分为多个变量 SAS
Using regex to split a sting into multiple variables SAS
我对 SAS 中正则表达式的使用有疑问。
我的数据集是这样的:
ID
Code
101
K2K5K8F10F26F2
102
L7P13P4
103
L1
我希望它看起来像这样:
ID
Code
101
K2
101
K5
101
K8
101
F10
101
F26
101
F2
102
L7
102
P13
102
P4
103
L1
一开始我认为先分配新列然后按行分配更容易。
我的尝试如下所示:
proc ds2;
data Codes (overwrite=yes);
dcl char(16) code1 code2 code3 code4 code5 code6;
dcl double re;
keep code1 code2 code3 code4 code5 code6;
retain re;
method init();
dcl varchar(32) expression;
expression = '/(\w+\d+)+/';
re=prxparse(expression);
if missing( re ) then do;
put 'ERROR: Invalid expression ' expression;
stop;
end;
end;
method run();
set mytable;
code1 = 'ERROR';
if prxmatch(re, Code) then
do;
code1=prxposn(re, 0, Code);
code2=prxposn(re, 1, Code);
code3=prxposn(re, 2, Code);
code4=prxposn(re, 3, Code);
code5=prxposn(re, 4, Code);
code6=prxposn(re, 5, Code);
end;
else do;
code1='0';
end;
end;
enddata;
run;
quit;
proc print data=Codes;
run;
quit;
但是,没有任何变化。结果,我得到了 code1 和 code2 列,就像初始数据集中的 Code 列一样被填充。我真的很感激任何帮助,因为正则表达式不是我的强项。我还将 code1 = 'ERROR' 和后来的 code1 = '0' 放在一起,以检查代码是否有效。
需要注意的是,我创建了code6作为试用。我不知道每个 ID 的确切代码数。但是,我知道代码必须始终是一个字母与一位或两位数字的组合,它也可以采用 Z12-9 的形式(因此一个字母后跟两位数字,然后是破折号,然后是一位数字).
提前致谢!
我发现这是 call scan
的一个特别好的用例,正则表达式的效率几乎没有。在这里,我使用 call scan
找到(总是单个)字母的“单词边界”,然后抓住它加上下一个字母(或单词结尾)之前的任何内容。
data have;
length code ;
input id code $;
datalines;
101 K2K5K8F10F26F2
102 L7P13P4
103 L1
;;;;
run;
data want;
set have;
do count = 1 to countw(code,,'a');
call scan(code,count,pos,len,,'a');
w = substr(code,pos-1,len+1);
output;
end;
run;
如果需要的话,我认为这在 DS2 中和数据步骤一样有效。
回答正则表达式部分,你的正则表达式是错误的,我认为 prxposn
可能也是错误的。
\w
匹配数字和字母,因此 \w+
将获取所有字符串。您需要使用 [A-Z]
,或使用 \w+?
以使用不太积极的匹配来仅获取单个字母然后数字集。
另外,这里正确的方法是call prxnext
,prxposn
匹配正则表达式中的每个括号匹配,所以1是第一个,2是第二个,但 (something)+
只有一个括号匹配。 call prxnext
将继续查找单个匹配项的更多匹配项,您可以使用它来获取匹配位。
这里也是简单的数据步骤,但 DS2 会类似。
data want;
set have;
rx = prxparse('/[A-Z]+\d+/ios');
start = 1;
do until (pos eq 0);
call prxnext(rx,start,length(code),code,pos,len);
if pos gt 0 then do;
w = substr(code,pos,len);
put w=;
output;
end;
end;
run;
我对 SAS 中正则表达式的使用有疑问。
我的数据集是这样的:
ID | Code |
---|---|
101 | K2K5K8F10F26F2 |
102 | L7P13P4 |
103 | L1 |
我希望它看起来像这样:
ID | Code |
---|---|
101 | K2 |
101 | K5 |
101 | K8 |
101 | F10 |
101 | F26 |
101 | F2 |
102 | L7 |
102 | P13 |
102 | P4 |
103 | L1 |
一开始我认为先分配新列然后按行分配更容易。
我的尝试如下所示:
proc ds2;
data Codes (overwrite=yes);
dcl char(16) code1 code2 code3 code4 code5 code6;
dcl double re;
keep code1 code2 code3 code4 code5 code6;
retain re;
method init();
dcl varchar(32) expression;
expression = '/(\w+\d+)+/';
re=prxparse(expression);
if missing( re ) then do;
put 'ERROR: Invalid expression ' expression;
stop;
end;
end;
method run();
set mytable;
code1 = 'ERROR';
if prxmatch(re, Code) then
do;
code1=prxposn(re, 0, Code);
code2=prxposn(re, 1, Code);
code3=prxposn(re, 2, Code);
code4=prxposn(re, 3, Code);
code5=prxposn(re, 4, Code);
code6=prxposn(re, 5, Code);
end;
else do;
code1='0';
end;
end;
enddata;
run;
quit;
proc print data=Codes;
run;
quit;
但是,没有任何变化。结果,我得到了 code1 和 code2 列,就像初始数据集中的 Code 列一样被填充。我真的很感激任何帮助,因为正则表达式不是我的强项。我还将 code1 = 'ERROR' 和后来的 code1 = '0' 放在一起,以检查代码是否有效。
需要注意的是,我创建了code6作为试用。我不知道每个 ID 的确切代码数。但是,我知道代码必须始终是一个字母与一位或两位数字的组合,它也可以采用 Z12-9 的形式(因此一个字母后跟两位数字,然后是破折号,然后是一位数字).
提前致谢!
我发现这是 call scan
的一个特别好的用例,正则表达式的效率几乎没有。在这里,我使用 call scan
找到(总是单个)字母的“单词边界”,然后抓住它加上下一个字母(或单词结尾)之前的任何内容。
data have;
length code ;
input id code $;
datalines;
101 K2K5K8F10F26F2
102 L7P13P4
103 L1
;;;;
run;
data want;
set have;
do count = 1 to countw(code,,'a');
call scan(code,count,pos,len,,'a');
w = substr(code,pos-1,len+1);
output;
end;
run;
如果需要的话,我认为这在 DS2 中和数据步骤一样有效。
回答正则表达式部分,你的正则表达式是错误的,我认为 prxposn
可能也是错误的。
\w
匹配数字和字母,因此 \w+
将获取所有字符串。您需要使用 [A-Z]
,或使用 \w+?
以使用不太积极的匹配来仅获取单个字母然后数字集。
另外,这里正确的方法是call prxnext
,prxposn
匹配正则表达式中的每个括号匹配,所以1是第一个,2是第二个,但 (something)+
只有一个括号匹配。 call prxnext
将继续查找单个匹配项的更多匹配项,您可以使用它来获取匹配位。
这里也是简单的数据步骤,但 DS2 会类似。
data want;
set have;
rx = prxparse('/[A-Z]+\d+/ios');
start = 1;
do until (pos eq 0);
call prxnext(rx,start,length(code),code,pos,len);
if pos gt 0 then do;
w = substr(code,pos,len);
put w=;
output;
end;
end;
run;