我想找到一个正则表达式,用我的自定义字符串%%
替换%
%s
和foobar
。这听起来很诡异,因为它应该将%%s
变成%s
而不会 %foobar
,所以这个天真的实现不起作用:
s/%%/%/g
s/%s/foobar/g
这个问题非常普遍,我在编程生涯中多次遇到过这个问题。不仅仅是百分比或百分比逃逸,还有反斜杠字符或反弹逃逸。我将发布我的常用解决方案,但我想知道是否有更好的方法。
(请允许我为将来的搜索做一些关键字填充:字符对,反斜杠反斜杠,反斜杠x,百分比,百分比s。谢谢。)
如果有特定的语言功能有助于此用例,我有兴趣了解它们是什么。
input : test %%, test %s, test %%s too
output : test %, test foobar, test %s too
另一个:
input : test%%,test%s,test%%stoo
output : test%,testfoobar,test%stoo
答案 0 :(得分:1)
这可以简化,可以在单replace
次电话中完成:
var str = "test %s, test %%, test %%s too";
var output = str.replace(/%%|(%s)/g, function($0, $1){
return $1!==undefined?'foobar':'%'; });
//=> test foobar, test %, test %s too
我们首先使用替换/%%/(%s)/
并在匹配(%s)
时使用捕获组。在replace callback
中,我们使用$1!==undefined
来决定要用作替代者的字符串。
答案 1 :(得分:1)
正则表达式是 - 如果你运行它们两次,它们会被应用两次。
所以是的 - 你的实施不会起作用,因为你要搜索两次' - 在你第一次更换之后,你无法区分它们。
那么呢?
#!/usr/bin/env perl
use strict;
use warnings;
my %replace = ( '%%' => '%',
'%s' => 'foobar' );
my $search = join ( "|", keys %replace );
$search = qr/($search)/;
print "Search regex: $search\n";
while ( <DATA> ) {
s/$search/$replace{$1}/g;
print;
}
##output : test %, test foobar, test %s too
##output : test%,testfoobar,test%stoo
__DATA__
test %%, test %s, test %%s too
test%%,test%s,test%%stoo
这样做很有意思,但是你正在构建一个查找表 - 捕获左侧,并在右侧查找它应该替换的内容。 (你也可以把它变成一个衬里)。
输出:
Search regex: (?^:(%%|%s))
test %, test foobar, test %s too
test%,testfoobar,test%stoo
非常确定你应该能够在大多数语言中实现这一点。
作为替代方案,它可能值得考虑正则表达式lookaround让你 - 如果你以相反的顺序做正则表达式:
#!/usr/bin/env perl
use strict;
use warnings;
while ( <DATA> ) {
s/(?<!%)%s/foobar/g;
s/%%/%/g;
print;
}
##output : test %, test foobar, test %s too
##output : test%,testfoobar,test%stoo
__DATA__
test %%, test %s, test %%s too
test%%,test%s,test%%stoo
(?<!%)
是一个零宽度断言,表示不会出现百分比&#39; - 所以它贯穿并用&#34; foobar&#34;替换 %s
。 (但忽略%%s
)。然后应用二次转换,它不会捕捉到foobar&#39; foobar&#39;因为那里没有%%
。
输出:
test %, test foobar, test %s too
test%,testfoobar,test%stoo
这种方法的缺点是并非所有语言都能正确支持环顾四周。 (这是一个先进的正则表达式&#39;事情,而不是&#39;基本&#39;)
答案 2 :(得分:1)
通过正则表达式替换不能最佳地解决转义序列的一般问题。
您必须将您的字符串视为由状态机以词汇方式评估的标记序列。
首先处于NORMAL
状态
在正常状态下,您遇到的任何字符都会按原样复制到输出中,除非它是%
,在这种情况下,您输入状态PERCENT
。
在该州,您可以遇到%
,然后输出%
并返回NORMAL
。
您还可以遇到s
,然后弹出下一个替换字符串,输出它,然后返回NORMAL
。
最后,根据您需要的行为,PERCENT
状态中遇到的任何其他字符都可能产生错误,或被忽略......
示例javascript代码:
function parseString(s, vars) {
var NORMAL = 0, PERCENT = 1;
var state = NORMAL;
var varidx = 0;
var output = '';
for (var i = 0; i < s.length; i++) {
if (state == NORMAL) {
if (s[i] == '%') {
state = PERCENT;
} else {
output += s[i];
}
} else if (state == PERCENT) {
if (s[i] == '%') {
output += s[i];
state = NORMAL;
} else if (s[i] == 's') {
output += vars[varidx++];
state = NORMAL;
} else {
throw 'Invalid syntax';
}
}
}
return output;
}
示例:
parseString("test %%, test %s, test %%s too", ['foo']);
// returns "test %, test foo, test %s too"
虽然这种方法的代码比基于regexp的解决方案更多,但它可能更快,因为正则表达式涉及更高程度的复杂性,并且它允许您以最适合您的方式处理无效语法。
答案 3 :(得分:0)
这是一种简单的方法。使用正则表达式/%%|%s|./
将字符串拆分为一个块数组,因为缺少更好的术语,以便每个块都是一个字符或转义字符,然后检查每个单独的块%s
和{ {1}}像这样,进行unescaping,再次加入数组,如下所示:
%%
Javascript中的相同想法没有使用变量来保存块:
Input : "test %s, test %%, test %%s too"
Array : ["t", "e", "s", "t", " ", "%s", ",", " ", "t", "e", "s", "t", " ", "%%",
" ", "t", "e", "s", "t", "%%", "s", " ", "t", "o", "o"]
Output : "test foobar, test %, test %s too"
答案 4 :(得分:0)
以%%
%
方式将%s
替换为foobar
,将string.replace(/%%|%s/g, function (match) {
// If %% is matched, replace it by %
// else %s is matched, replace by `foobar`
return match === '%%' ? '%' : 'foobar';
});
替换为var str = "test %s, test %%, test %%s too";
str = str.replace(/%%|%s/g, function (_) {
return _ === '%%' ? '%' : 'foobar';
});
console.log(str);
document.body.innerHTML = str;
。
str
.replace(/%%/g, '2percent') // Replace first string by some string that will not possibly be appear/present in the main string
.replace(/%s/g, 'foobar') // Replace second string
.replace(/2percent/g, '%'); // Replace temp by the normal string
var str = "test %s, test %%, test %%s too";
str = str
.replace(/%%/g, '2percent')
.replace(/%s/g, 'foobar')
.replace(/2percent/g, '%');
console.log(str);
document.body.innerHTML = str;
使用此方法,javascript仅使用一次,而不是其他答案的三倍。
这是使用临时变量的变量交换逻辑的另一种方法。
与String#replace
search/list
part=snippet