空格的SAS处理会干扰正则表达式规则



我有一个数据集,需要使用regex规则进行清理。这些规则来自具有列string_patternstring_replace的文件regex_rules.csv,并使用prxparseprxchange的组合应用,如下所示:

array a_rules{1:&NOBS} $200. _temporary_;
array a_rules_parsed{1:&num_rules} _temporary_;
if _n_ = 1 then
do i = 1 to &num_rules;
a_rules{i} = cat("'s/",string_pattern,"/",string_replace,"/'");
a_rules_parsed{i} = prxparse(cats('s/',string_pattern,'/',string_replace,'/','i'));
end
set work.dirty_strings;
clean_string = dirty_string;
do i = 1 to &num_rules;
debug_string = cats("Executing prxchange(",a_rules{i},",",-1,",","'",clean_string,"'",")");
put debug_string;
clean_string = PRXCHANGE(a_rules_parsed{i},-1,clean_string);
end

有些规则指定用单个空格替换某些模式,因此文件中相应的string_replace值为单个空格。

我面临的问题是,SAS从不尊重单个空间,而是用空字符串替换这些记录的匹配string_pattern(其他规则按预期应用(。

为了进行故障排除,我执行了以下操作:

proc sql;
create table work.single_blanks as
select
string_pattern,
string_replace,
from work.regex_rules
where string_replace = " ";
quit;

这产生了预期的记录。我很困惑地发现,将where子句改为where string_replace = ""where string_replace = " "给出了相同的结果!(我已经使用sas一段时间了,但我想这种行为直到现在都没有被注意到(。因此,我无法确定SAS是否忽略了正确读取文件并保留单个空白,或者prx函数之一是否未能正确处理单个空白。

我能想到";"黑客";解决方法,但我更想了解我在这里做错了什么,正确的解决方案应该是什么。

编辑1:

以下是文件中的一条规则,以及我希望它如何作用于示例输入值:

string_pattern, string_replace  
"(#|,|/|')", " "

在输入串CCD_ 10上运行上述代码不会产生预期的输出"0";10 120 DIRTY DRIVE";而是";10120 DIRTY DRIVE";。

编辑2

除了不尊重单个空格外,前导空格和尾随空格似乎也不受尊重。例如,对于具有规则的文件

string_pattern, string_replace  
"\bDR(\.|\b)", "DRIVE "
"\bS(\.|\b)?W(\.|\b)", " SOUTH WEST"

在输入串CCD_ 11上运行上述代码不会产生预期的输出"0";10120 DIRTY DRIVE SOUTH WEST";而是";10120脏驱动器开关&";。这是因为第一个string_replace值末尾的空间丢失,这意味着在第二个string_pattern的开头没有要匹配的单词边界。

SAS将字符变量存储为用空格填充的固定长度字符串。因此,字符串比较会忽略尾部空格。因此CCD_ 14和CCD_。

CATS()将删除所有前导和尾随空格,因此空字符串将不会生成任何内容。听起来你想把一个空字符串当作一个空格。TRIM((函数将为一个空字符串返回一个空格。所以也许你只想改变这个:

cats('s/',string_pattern,'/',string_replace,'/','i')

进入

cat('s/',trim(string_pattern),'/',trim(string_replace),'/','i')

以下是示例数据的工作代码(具有固定的字符串模式(:

data test;
length string_pattern string_replace dirty_string expect 
clean_string regex $200
;
infile cards dsd truncover;
input  string_pattern string_replace dirty_string expect;
regex= cat('s/',trim(string_pattern),'/',trim(string_replace),'/i') ;
regex_id = prxparse(trim(regex));
clean_string = prxchange(regex_id,-1,trim(dirty_string));
if clean_string=expect then put 'GOOD'; else put 'BAD';
*put (_character_) (=$quote./);
cards4;
"(#|,|/|')", " ","10,120 DIRTY DRIVE","10 120 DIRTY DRIVE"
;;;;

如果您的任何值都有显著的尾随空格,那么您将需要以不同的方式存储数据。例如,您可以引用以下值:

string_replace = "'DRIVE '";   
...
cat('s/',dequote(string_pattern),'/',dequote(string_replace),'/','i')

如果只在需要引号的值周围添加引号,则需要包含TRIM((函数调用。

cat('s/',dequote(trim(string_pattern)),'/',dequote(trim(string_replace)),'/','i')

或者将字符串长度存储到单独的数字字段中。

cat('s/',substrn(string_pattern,1,len1),'/',substrn(string_replace,1,len2),'/','i')

请注意,如果您的任何原始字符串都有显著的前导或尾随空格,那么通过从CSV文件中读取数据,它们就会被消除。

最新更新