SAS 将文本写入文本文件会导致额外的空间未写入 LOG 文件

SAS Writing text to a text file results in extra spaces not written to the LOG file

我有一个地址标准化数据集——使用 STREET 并将其替换为 ST——并希望编写执行替换的代码。测试代码时,它按预期出现在 LOG 文件中,但是当我写入文本文件时会添加额外的空格。我不想要多余的空格。

-=-=-=-=-=- SAS 代码

   data std ;
    
        length pre  post  ;
        infile datalines delimiter=',' ;
        input pre $ post $ ;
        
    pre = strip(pre);
    post = strip(post);
    
    datalines;  
    AVENUES ,   AVE
    AVENUE  ,   AVE
    BOULEVARD   ,   BLVD
    CIRCLE  ,   CIR
    ;
    run;
    
    data _null_ ;
    
        file "&test.txt";
        set std ;
        
    p1  =   trim(pre) ;
    p2  =   trim(post);
        
    put '&var = strip( prxchange("s/(^|\s)' p1 +(-1) '\s/ ' p2 +(-1) ' /i",-1,&var) );' ;
    
    run;

-=-=-=-=-=-=-=- 代码结束

SAS 代码产生以下...

&var = strip( prxchange("s/(^|\s)AVENUES\s/ AVE /i",-1,&var) );

 &var = strip( prxchange("s/(^|\s)AVENUE\s/ AVE /i",-1,&var) );

 &var = strip( prxchange("s/(^|\s)BOULEVARD\s/ BLVD /i",-1,&var) );

...当我删除文件语句时,在 LOG 文件中写入...

&var = strip( prxchange("s/(^|\s)AVENUES    \s/     AVE /i",-1,&var) );

&var = strip( prxchange("s/(^|\s)AVENUE \s/     AVE /i",-1,&var) );

&var = strip( prxchange("s/(^|\s)BOULEVARD  \s/     BLVD /i",-1,&var) );

...在文件 test.txt.

的 REGEX 函数内有额外的空格

这是我通过基于网络的 SAS Studio 使用的 SAS 9.4。

所以,您的问题是基于 SAS 如何存储字符变量。

字符变量 总是 等于存储在该变量中的字符,后跟根据需要填充的 space ('20'x) 个字符数据存储的长度。这不同于(大多数较新的)具有字符串终止符或类似字符的语言; SAS 没有这样的字符,它只是用 space 填充 space。所以如果变量是 8 个字节长,并且包含 Avenue,那么它实际上包含 Avenue .

无法在单行代码之外的代码中更改。所以,你的台词:

p1  =   trim(pre) ;
p2  =   trim(post);

毫无意义 - 它们除了浪费 CPU 时间外什么都不做(遗憾的是,没有根据我的判断进行优化)。

您需要 trim 在您使用值 的行中,因为它可以被 trim 消除。现在,你不能 put 一个 trim(...),所以你需要把你的行写在别处,或者使用 $varying. format.

这是一个例子:

filename tempfile temp;

data _null_ ;    
    file tempfile;
    set std ;        
    result = cats('&var = strip( prxchange("s/(^|\s)',pre,catx(' ','\s/',post,'/i",-1,&var) );'));
    put  result ;

run;

data _null_;
  infile tempfile;
  input @;
  put _infile_;
run;

这是一个使用 $varying. 的例子:

data _null_ ;    
    file tempfile;
    set std ;        
    varlen_pre = length(pre);
    varlen_post = length(post);
      put '&var = strip( prxchange("s/(^|\s)' pre $varying16. varlen_pre  '\s/ ' post $varying8. varlen_post  ' /i",-1,&var) );' ;

run;

至于为什么你的日志与文件不匹配,那是因为SAS写入日志的规则与写入文件的规则略有不同。它对写入文件的内容更加准确;你说它,它写它。对于日志,它有几个地方会为您删除 spaces,大概是为了使日志更具可读性,因为它没有必要那么精确。当您确实想要日志中的精度时,这可能会很痛苦,当然在您希望日志与您所看到的相匹配的情况下...


最后,请注意您的操作。我不强烈建议按照您使用正则表达式的方式使用它。它非常 慢。除非您只进行少量替换,或者数据集很小,或者真的不关心这需要多长时间...

如果只是 1:1 替换,我建议 tranwrd,这样会更快。看看这个小比较:

data in_data;
  do _n_ = 1 to 1e5;
    address = catx(' ',rand('Integer',1,9999),'Avenue');
    output;
    address = catx(' ',rand('Integer',1,9999),'Street');
    output;
    address = catx(' ',rand('Integer',1,9999),'Boulevard');
    output;
    address = catx(' ',rand('Integer',1,9999),'Circle');
    output;
    address = catx(' ',rand('Integer',1,9999),'Route');
    output;
    
  end;
run;

data want;
  set in_data;

  rx_ave  = prxparse('s/(^|\s)Avenue\s/ Ave /ios');
  rx_st   = prxparse('s/(^|\s)Street\s/ St/ios');
  rx_blvd = prxparse('s/(^|\s)Boulevard\s/ Blvd /ios');
  rx_cir  = prxparse('s/(^|\s)Circle\s/ Cir /ios');
  
  do i = 1 to 4;
    address = prxchange(i,-1,address);
  end;
run;

data want;
  set in_data; 
    address = tranwrd(Address,'Avenue','Ave');
    address = tranwrd(address,'Street','St');
    address = tranwrd(address,'Boulevard','Blvd');
    address = tranwrd(address,'Circle','Cir');
run;

两者的工作原理相同 - 假设你已经在使用 'words' - 但第二个基本上是写出数据集所需的时间(对我来说是 0.15 秒),而第一个需要 20 秒CPU 时间在我的 SAS 服务器上。加载正则表达式库真的很慢。