使用正则表达式将字符串拆分为多个变量 SAS

Posted

技术标签:

【中文标题】使用正则表达式将字符串拆分为多个变量 SAS【英文标题】:Using regex to split a sting into multiple variables SAS 【发布时间】:2022-01-20 11:14:51 【问题描述】:

我对 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 的形式(所以一个字母后跟两个数字,然后是一个破折号,然后是一个数字)。

提前谢谢你!

【问题讨论】:

您使用 PROC DS2 是否有特定原因?这是要求吗?这里的数据步骤相当简单。 这不是必需的,它只是从我使用过的旧代码库中复制而来。但我明白你的意思:) 【参考方案1】:

回答这部分的正则表达式,你的正则表达式是错误的,我认为prxposn可能也是错误的。

\w 匹配数字和 alpha,因此 \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;

【讨论】:

【参考方案2】:

我发现这是call scan 的一个特别好的用例,正则表达式几乎没有那么有效。在这里,我使用call scan 来查找(始终为单个)字母的“单词边界”,然后将其加上下一个字母(或词尾)之前的任何内容。

data have;
length code $20 ;
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 和数据步骤中都可以使用。

【讨论】:

以上是关于使用正则表达式将字符串拆分为多个变量 SAS的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式拆分简单的 JSON 结构

使用正则表达式将字符串拆分为句子

使用正则表达式将字段拆分为数组的 Bash 脚本用于多字符分隔符

根据字符串(正则表达式)将一行拆分为更多行

C ++拆分字符串基于/使用(增强)正则表达式来查找令牌

根据正则表达式拆分字符串