Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在替换子字符串时防止令牌注入_Java_Regex - Fatal编程技术网

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()
正确转义文字替换模式。