使用正则表达式将字符串拆分为多个变量 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 prxnextprxposn匹配正则表达式中的每个括号匹配,所以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;