简体   繁体   English

替换子字符串时防止令牌注入

[英]Preventing token injection when replacing substrings

I have a list of key/value strings and a template to replace them in. However, I don't want to replace them twice if one of the values is another token.我有一个键/值字符串列表和一个用于替换它们的模板。但是,如果其中一个值是另一个标记,我不想替换它们两次。 For example:例如:

tokens: [
    Token(Key: "{A}", Value: "{B}"),
    Token(Key: "{B}", Value: "b" )
]

template = "Hello, {A}"

>>> replace(template, tokens)
Actual: "b"
Expected: "{B}"

Here's the code:这是代码:

import java.util.regex.*;

class Main {

  public static String replace(String template, Token... tokens) {
    for ( final Token token : tokens ) {
        template = Pattern.compile( token.getKey(), Pattern.LITERAL + Pattern.CASE_INSENSITIVE )
               .matcher( template )
               .replaceAll( Matcher.quoteReplacement( token.getValue() ) );
    }
    return template;
  }


  public static void main(String[] args) {
    String result = replace( "Hello, {A}",
                            new Token("{A}", "{B}"),
                            new Token("{B}", "b" ) );
    System.out.println(result);
  }


  private static class Token {
    String key;
    String value;

    public Token(String key, String value) {
      this.key = key;
      this.value = value;
    }

    public String getKey() {
      return key;
    }

    public String getValue() {
      return value;
    }
  }
}

This must also work for special characters:这也必须适用于特殊字符:

replace("{A}", new Token("{A}", "$0.00")) -> "$0.00"

The point here is to parse the string with the regex only once , make only one pass and when you match your key pattern, it is just {[^{}]*} , any substring between { and } with no curly braces in between, check if there is a token with this key in your Token list, and if there is, replace with this token value, else, put the matched text back.这里的要点是只用正则表达式解析字符串一次,只通过一次,当你匹配你的键模式时,它只是{[^{}]*} ,任何 substring 之间的{}之间没有花括号, 检查你的Token列表中是否有这个键的 token,如果有,用这个 token 值替换,否则,把匹配的文本放回去。

You may use您可以使用

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();
}

The main method code executed like主要方法代码执行如下

public static void main(String[] args) {
    String result = replace( "Hello, {A} {c}",
                            new Token("{A}", "{B}"),
                            new Token("{B}", "b" ) );
    System.out.println(result);
}

will output Hello, {B} {c} .将 output Hello, {B} {c}

See the Java demo online .在线查看 Java 演示

The if (token.getKey().toUpperCase().equals(key.toUpperCase())) line ensures the case insensitive matching. if (token.getKey().toUpperCase().equals(key.toUpperCase()))行确保不区分大小写的匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM