Java 在替换子字符串时防止令牌注入
我有一个键/值字符串列表和一个替换它们的模板。但是,如果其中一个值是另一个标记,我不想替换它们两次。例如:Java 在替换子字符串时防止令牌注入,java,regex,Java,Regex,我有一个键/值字符串列表和一个替换它们的模板。但是,如果其中一个值是另一个标记,我不想替换它们两次。例如: tokens: [ Token(Key: "{A}", Value: "{B}"), Token(Key: "{B}", Value: "b" ) ] template = "Hello, {A}" >>> replace(template, token
tokens: [
Token(Key: "{A}", Value: "{B}"),
Token(Key: "{B}", Value: "b" )
]
template = "Hello, {A}"
>>> replace(template, tokens)
Actual: "b"
Expected: "{B}"
代码如下:
import java.util.regex.*;
班长{
公共静态字符串替换(字符串模板、令牌…令牌){
for(最终令牌:令牌){
template=Pattern.compile(token.getKey(),Pattern.LITERAL+Pattern.CASE\u不区分大小写)
.matcher(模板)
.replaceAll(Matcher.quoterReplace(token.getValue());
}
返回模板;
}
公共静态void main(字符串[]args){
String result=replace(“你好,{A}”,
新标记(“{A},“{B}”),
新标记(“{B}”、“B”);
系统输出打印项次(结果);
}
私有静态类令牌{
字符串键;
字符串值;
公共令牌(字符串键、字符串值){
this.key=key;
这个值=值;
}
公共字符串getKey(){
返回键;
}
公共字符串getValue(){
返回值;
}
}
}
这也必须适用于特殊字符:
replace("{A}", new Token("{A}", "$0.00")) -> "$0.00"
这里的要点是只使用正则表达式解析字符串一次,只进行一次传递,当您匹配密钥模式时,它只是
{[^{}]*}
,介于{
和}
之间的任何子字符串,中间没有花括号,检查令牌
列表中是否有带此密钥的令牌,如果有,替换为该标记值,否则,将匹配的文本放回
你可以用
public static final Pattern keypattern = Pattern.compile("\\{[^{}]*}");
public static Token getTokenByKey(String key, Token... tokens) {
for ( final Token token : tokens ) {
if (token.getKey().toUpperCase().equals(key.toUpperCase()))
return token;
}
return null;
}
public static String replace(String template, Token... tokens) {
Matcher m = keypattern.matcher( template );
StringBuffer sb = new StringBuffer();
while (m.find()) {
Token t = getTokenByKey(m.group(), tokens);
if (t != null) {
m.appendReplacement(sb, Matcher.quoteReplacement(t.getValue()));
} else {
m.appendReplacement(sb, Matcher.quoteReplacement(m.group()));
}
}
m.appendTail(sb);
return sb.toString();
}
主方法代码执行如下
public static void main(String[] args) {
String result = replace( "Hello, {A} {c}",
new Token("{A}", "{B}"),
new Token("{B}", "b" ) );
System.out.println(result);
}
将输出Hello,{B}{c}
看
if(token.getKey().toUpperCase().equals(key.toUpperCase())
行确保不区分大小写的匹配。您能分享一个可复制的演示吗?例如,在repl.it、ideone.com、tio.run、rextester.com……上面的代码非常容易理解。它遍历每个令牌,并用其值替换其密钥的所有实例。但是,如果一个令牌的值是下一个(或下一个)令牌的密钥,它将再次被替换。我知道如何修复它,我只想在您的数据上进行测试。只是不要迭代令牌。根据您的语法使用匹配任何标记的模式,{.*?}
等等,迭代匹配,并根据某些查找替换为相应的标记。@WiktorStribiżew这几乎可以完美地工作。但是,如果令牌值具有特殊字符($0.00->{A}.00
)@MichaelBianconi,则它会中断。现在还不清楚。什么是令牌密钥,什么是值?请编辑问题。键:“{A}”,值:“$0.00”,模式:“{A}”,结果:“{A}.00”@MichaelBianconi确定,使用Matcher.quoteReplacement()
正确转义文字替换模式。