如何用等长星号替换引号中的文本?
How to replace text in quotes with equal length asterisks?
如何在 SAS 中用相同长度的星号替换引号中的文本?
我的意思是,转换:
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
至:
*******
******
**********************
there are ************* not in quotes
第1,2,3,4行分别有7,6,22,13个星号。是的,引号本身也包括在内。
我试过这样的程序:
pat=prxparse('/[''"].*?["'']/');
do until(pos=0);
call prxsubstr(pat,text,pos,len);
if pos then substr(text,pos,len)=repeat('*',len-1);
end;
有效。
我的问题是:有没有更有效的方法来做到这一点?
首先,您的示例在第三个表达式上失败,因为它不记得开头引号是什么 - 所以它使“double”不匹配。
您可以使用 SAS 支持的反向引用解决该问题:
data have;
length text 24;
infile datalines pad;
input @1 text .;
datalines;
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
;;;;
run;
data want;
set have;
pat=prxparse('/([''"]).*?/');
do until(pos=0);
call prxsubstr(pat,text,pos,len);
if pos then substr(text,pos,len)=repeat('*',len-1);
end;
run;
效率方面,这在我的(相当快但不是特别快)SAS 服务器上处理 400k 记录(这 4 x 100,000)大约需要 1.5 秒。这似乎是合理的,除非您的文本更大或行数更大。另外,请注意,如果允许的话,这将在高度复杂的嵌套上失败(single-double-single 等,或者 single 中的 double-single 不会被识别,尽管它可能仍然可以很好地满足您的意图)。
但是,如果您想要最高效,正则表达式不是答案 - 使用基本文本函数效率更高。但是要完全正确更难,并且需要更多的代码,所以如果正则表达式的性能可以接受,我不建议这样做。但这是一个例子——您可能需要对其进行一些调整,并且您需要循环它以重复直到它找不到任何要替换的内容,如果根本没有引号则不执行它。这只是给出了如何使用文本函数的基本概念。
data want;
set have;
length text_sub ;
_start = findc(text,'"''');
_qchar = char(text,_start); *Save aside which char we matched on;
_end = findc(text,_qchar,_start+1); *now look for that one again anywhere after the first match;
to_convert = substr(text,_start,_end-_start+1);
if _start eq 1 and _end eq length(text) then text_sub = repeat('*',_end-1);
else if _start eq 1 then text_sub = substr(text,_end+1);
else if _end eq length(text) then text_sub = substr(text,1,_start-1)||repeat('*',_end-_start);
else text_sub = cat(substr(text,1,_start-1),repeat('*',_end-_start),substr(text,_end+1));
run;
我会跳过正则表达式,只使用 CALL SCAN() 代替。
所以循环查找下一个“单词”的位置。如果单词以引号开头和结尾,则用 * 替换单词。
data have;
input string $char80. ;
cards;
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
What's going on?
;
data want;
set have;
position=1;
do count=1 by 1 while(position>0);
call scan(string,count,position,length,' ','q');
if char(string,position) in ('"',"'")
and char(string,position)=char(string,position+length-1)
then substr(string,position,length) = repeat('*',length-1)
;
end;
drop position count length;
run;
结果
Obs string
1 *******
2 ******
3 **********************
4 there are ************* not in quotes
5
6 What's going on?
如何在 SAS 中用相同长度的星号替换引号中的文本? 我的意思是,转换:
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
至:
*******
******
**********************
there are ************* not in quotes
第1,2,3,4行分别有7,6,22,13个星号。是的,引号本身也包括在内。
我试过这样的程序:
pat=prxparse('/[''"].*?["'']/');
do until(pos=0);
call prxsubstr(pat,text,pos,len);
if pos then substr(text,pos,len)=repeat('*',len-1);
end;
有效。
我的问题是:有没有更有效的方法来做到这一点?
首先,您的示例在第三个表达式上失败,因为它不记得开头引号是什么 - 所以它使“double”不匹配。
您可以使用 SAS 支持的反向引用解决该问题:
data have;
length text 24;
infile datalines pad;
input @1 text .;
datalines;
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
;;;;
run;
data want;
set have;
pat=prxparse('/([''"]).*?/');
do until(pos=0);
call prxsubstr(pat,text,pos,len);
if pos then substr(text,pos,len)=repeat('*',len-1);
end;
run;
效率方面,这在我的(相当快但不是特别快)SAS 服务器上处理 400k 记录(这 4 x 100,000)大约需要 1.5 秒。这似乎是合理的,除非您的文本更大或行数更大。另外,请注意,如果允许的话,这将在高度复杂的嵌套上失败(single-double-single 等,或者 single 中的 double-single 不会被识别,尽管它可能仍然可以很好地满足您的意图)。
但是,如果您想要最高效,正则表达式不是答案 - 使用基本文本函数效率更高。但是要完全正确更难,并且需要更多的代码,所以如果正则表达式的性能可以接受,我不建议这样做。但这是一个例子——您可能需要对其进行一些调整,并且您需要循环它以重复直到它找不到任何要替换的内容,如果根本没有引号则不执行它。这只是给出了如何使用文本函数的基本概念。
data want;
set have;
length text_sub ;
_start = findc(text,'"''');
_qchar = char(text,_start); *Save aside which char we matched on;
_end = findc(text,_qchar,_start+1); *now look for that one again anywhere after the first match;
to_convert = substr(text,_start,_end-_start+1);
if _start eq 1 and _end eq length(text) then text_sub = repeat('*',_end-1);
else if _start eq 1 then text_sub = substr(text,_end+1);
else if _end eq length(text) then text_sub = substr(text,1,_start-1)||repeat('*',_end-_start);
else text_sub = cat(substr(text,1,_start-1),repeat('*',_end-_start),substr(text,_end+1));
run;
我会跳过正则表达式,只使用 CALL SCAN() 代替。
所以循环查找下一个“单词”的位置。如果单词以引号开头和结尾,则用 * 替换单词。
data have;
input string $char80. ;
cards;
"12345"
"hi42"
'with "double" quotes'
there are 'other words' not in quotes
What's going on?
;
data want;
set have;
position=1;
do count=1 by 1 while(position>0);
call scan(string,count,position,length,' ','q');
if char(string,position) in ('"',"'")
and char(string,position)=char(string,position+length-1)
then substr(string,position,length) = repeat('*',length-1)
;
end;
drop position count length;
run;
结果
Obs string
1 *******
2 ******
3 **********************
4 there are ************* not in quotes
5
6 What's going on?