如何查找和替换SAS数据集中的特定文本?

时间:2016-07-07 20:05:55

标签: replace sas dataset

我有一个数据集,其中包含400个4位数代码的观察值,我想用两边的空格填充

ex. Dataset 
obs code
1   1111 
2   1112
3   3333
.
.
.
400 5999

如何通过另一个大型数据集并用“”替换任何填充的400个代码的每个匹配项。

ex. Large Dataset
obs text 
1   abcdef 1111 abcdef
2   abcdef 1111 abcdef 1112 8888
3   abcdef 1111 abcdef 11128888
... 

我想要的数据集

ex. New Data set
obs text
1   abcdef   abcdef
2   abcdef   abcdef   8888
3   abcdef   abcdef 11128888
...

注意:我只想替换两边用空格填充的4位数代码。所以在obs 3中,1112不会被替换。

我尝试过以下proc sql语句,但它只找到并替换第一个匹配,而不是所有匹配。

proc sql;  
    select   
    *,  
    tranwrd(large_dataset.text, trim(small_dataset.code), ' ') as new_text  
from large_dataset  
    left join small_dataset  
    on findw(large_dataset.text, trim(small_dataset.code))
;
quit;

4 个答案:

答案 0 :(得分:3)

您可以使用DO循环扫描大型数据集中每条记录的小代码数据集。如果您想使用TRANWRD()功能,则需要添加额外的空格字符。

data want ;
  set have ;
  length code $4 ;
  do i=1 to nobs while (text ne ' ');
    set codes(keep=code) nobs=nobs point=i ;
    text = substr(tranwrd(' '||text,' '||code||' ',' '),2);
  end;
  drop code;
run;

DO循环将读取CODES列表中的记录。使用SET语句中的POINT =选项可以多次读取文件。如果TEXT字符串为空,WHILE子句将停止,因为此时无需继续查找要替换的代码。

如果您的代码列表足够小并且您可以获得正确的正则表达式,那么您可以尝试使用PRXCHANGE()函数。您可以使用SQL步骤将代码生成为可在正则表达式中使用的列表。

proc sql noprint ;
  select code into :codelist separated by '|'
  from codes
;
quit;

data want ;
  set have ;
  text=prxchange("s/\b(&codelist)\b/ /",-1,text);
run;

答案 1 :(得分:0)

可能有更有效的方法来做到这一点,但这似乎运作得相当好:

/*Create test datasets*/
data codes;
input code;
cards;
1111 
1112
3333
5999
;
run;

data big_dataset;
infile cards truncover;
input text $100.;
cards;
abcdef 1111 abcdef
abcdef 1111 abcdef 1112 8888
abcdef 1111 abcdef 11128888
;
run;

/*Get the number of codes to use for array definition*/
data _null_;
    set codes(obs = 1) nobs = nobs;
    call symput('ncodes',nobs);
run;

%put ncodes = &ncodes;

data want;
    set big_dataset;
    /*Define and populate array with padded codes*/ 
    array codes{&ncodes} $6 _temporary_;
    if _n_ = 1 then do i = 1 to &ncodes;    
        set codes;
        codes[i] = cat(' ',put(code,4.),' '); 
    end;
    do i = 1 to &ncodes;
        text = tranwrd(text,codes[i],' ');
    end;
    drop i code;
run;

我希望使用prxchange的解决方案也是可行的,但是我不确定构建匹配所有代码的正则表达式与仅逐个替换它们相比有多少工作量。< / p>

答案 2 :(得分:0)

采用Tom的解决方案并将代码查找放入哈希表中。因此,数据集将仅被读取一次并且实际查找非常快。如果大数据集非常大,这将产生巨大的差异。

data want ;
  if _n_ = 1 then do;
    length code $4 ;
    declare hash h(dataset:"codes (keep=code)") ; 
    h.defineKey("code") ;
    h.defineDone() ;
    call missing (code);
    declare hiter hiter('h') ;
  end;
  set big_dataset ;

  rc = hiter.first() ;
  do while (rc = 0 and text ne ' ') ;
    text = substr(tranwrd(' '||text,' '||code||' ',' '),2) ;
    rc = hiter.next() ;
  end ;
  drop code rc ;
run;

答案 3 :(得分:0)

使用数组和常规快递:

proc transpose data=codes out=temp;
var code;
run;

data want;
if _n_=1 then  set temp;
array var col:;
set big_dataset;
do over var;
text = prxchange(cats('s/\b',var,'\b//'),-1,text);
end;
drop col:;
run;