在Python中,格式化字符串时,我可以按名称而不是按位置填充占位符,如下所示:

print "There's an incorrect value '%(value)s' in column # %(column)d" % \
  { 'value': x, 'column': y }

我想知道这在Java中是否可能(希望没有外部库)?


当前回答

不幸的是,答案是否定的。然而,你可以非常接近一个合理的语法:

"""
   You are $compliment!
"""
.replace('$compliment', 'awesome');

它比String更具可读性和可预测性。至少是格式!

其他回答

你可以使用StringTemplate库,它提供了你想要的和更多。

import org.antlr.stringtemplate.*;

final StringTemplate hello = new StringTemplate("Hello, $name$");
hello.setAttribute("name", "World");
System.out.println(hello.toString());

Apache Commons Lang的replaceEach方法可能会根据您的特定需求派上用场。你可以简单地用这个方法调用来替换占位符:

StringUtils.replaceEach("There's an incorrect value '%(value)' in column # %(column)",
            new String[] { "%(value)", "%(column)" }, new String[] { x, y });

给定一些输入文本,这将用第二个字符串数组中的相应值替换第一个字符串数组中出现的所有占位符。

试试Freemarker,模板库。

这是一个旧的线程,但只是为了记录,你也可以使用Java 8风格,像这样:

public static String replaceParams(Map<String, String> hashMap, String template) {
    return hashMap.entrySet().stream().reduce(template, (s, e) -> s.replace("%(" + e.getKey() + ")", e.getValue()),
            (s, s2) -> s);
}

用法:

public static void main(String[] args) {
    final HashMap<String, String> hashMap = new HashMap<String, String>() {
        {
            put("foo", "foo1");
            put("bar", "bar1");
            put("car", "BMW");
            put("truck", "MAN");
        }
    };
    String res = replaceParams(hashMap, "This is '%(foo)' and '%(foo)', but also '%(bar)' '%(bar)' indeed.");
    System.out.println(res);
    System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(foo)', but also '%(bar)' '%(bar)' indeed."));
    System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(truck)', but also '%(foo)' '%(bar)' + '%(truck)' indeed."));
}

输出将是:

This is 'foo1' and 'foo1', but also 'bar1' 'bar1' indeed.
This is 'BMW' and 'foo1', but also 'bar1' 'bar1' indeed.
This is 'BMW' and 'MAN', but also 'foo1' 'bar1' + 'MAN' indeed.

在编写本文时,Java中还没有内置任何东西。我建议编写自己的实现。我的偏好是一个简单流畅的构建器接口,而不是创建一个映射并将其传递给函数——你最终会得到一个漂亮的连续代码块,例如:

String result = new TemplatedStringBuilder("My name is {{name}} and I from {{town}}")
   .replace("name", "John Doe")
   .replace("town", "Sydney")
   .finish();

下面是一个简单的实现:

class TemplatedStringBuilder {

    private final static String TEMPLATE_START_TOKEN = "{{";
    private final static String TEMPLATE_CLOSE_TOKEN = "}}";

    private final String template;
    private final Map<String, String> parameters = new HashMap<>();

    public TemplatedStringBuilder(String template) {
        if (template == null) throw new NullPointerException();
        this.template = template;
    }

    public TemplatedStringBuilder replace(String key, String value){
        parameters.put(key, value);
        return this;
    }

    public String finish(){

        StringBuilder result = new StringBuilder();

        int startIndex = 0;

        while (startIndex < template.length()){

            int openIndex  = template.indexOf(TEMPLATE_START_TOKEN, startIndex);

            if (openIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            int closeIndex = template.indexOf(TEMPLATE_CLOSE_TOKEN, openIndex);

            if(closeIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            String key = template.substring(openIndex + TEMPLATE_START_TOKEN.length(), closeIndex);

            if (!parameters.containsKey(key)) throw new RuntimeException("missing value for key: " + key);

            result.append(template.substring(startIndex, openIndex));
            result.append(parameters.get(key));

            startIndex = closeIndex + TEMPLATE_CLOSE_TOKEN.length();
        }

        return result.toString();
    }
}