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 服务器上。加载正则表达式库真的很慢。
我有一个地址标准化数据集——使用 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 服务器上。加载正则表达式库真的很慢。