我有一个数据集,需要使用regex规则进行清理。这些规则来自具有列string_pattern
和string_replace
的文件regex_rules.csv
,并使用prxparse
和prxchange
的组合应用,如下所示:
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文件中读取数据,它们就会被消除。