4

在 Python 中,我们可以很容易地做到这一点:

data = {'name':'Felix'}
s = 'Hello, %(name)s' % data
s
'Hello, Felix'

Java中是否有类似的方法来实现相同的东西?

PS:对不起,不清楚的问题。用例是:我们有一个存储键值的映射,模板只需要在映射中指定一个键,那么键的值就会在模板中键所在的位置。

4

5 回答 5

3

AFAIK 你可以用String#format这个:

String name = "Felix";
String s = String.format("Hello, %s", name);
System.out.println(s);

这将打印

Hello, Felix

有关如何使用格式的更多信息String#format可以在java.util.Formatter语法中找到

于 2013-07-26T03:01:16.733 回答
1

如果您只想用字符串替换字符串,那么我答案第二部分的代码会更好

Java Formatter类不支持%(key)s表单,但您可以使用%index$swhere index is counted from 1 like in this example

System.out.format("%3$s, %2$s, %1s", "a", "b", "c");
// indexes                            1    2    3

输出:

c, b, a

因此,您需要做的就是创建一些数组,该数组将包含模式中使用的值并将键名更改为其相应的索引(增加 1,因为 Formatter 使用的第一个索引的编写方式1$0$我们对数组索引的预期不同)。

这是将为您执行此操作的方法示例

// I made this Pattern static and put it outside of method to compile it only once,
// also it will match every (xxx) that has % before it, but wont include %
static Pattern formatPattern = Pattern.compile("(?<=%)\\(([^)]+)\\)");

public static String format(String pattern, Map<String, ?> map) {
    StringBuffer sb = new StringBuffer();
    List<Object> valuesList = new ArrayList<>();

    Matcher m = formatPattern.matcher(pattern);

    while (m.find()) {

        String key = m.group(1);//group 1 contains part inside parenthesis

        Object value = map.get(key);
        // If map doesn't contain key, value will be null.
        // If you want to react somehow to null value like throw some
        // Exception
        // now is the good time.

        if (valuesList.contains(value)) {
            m.appendReplacement(sb, (valuesList.indexOf(value) + 1) + "\\$");
        } else {
            valuesList.add(value);
            m.appendReplacement(sb, valuesList.size() + "\\$");
        }
    }
    m.appendTail(sb);

    return String.format(sb.toString(), valuesList.toArray());
}

用法

Map<String, Object> map = new HashMap<>();
map.put("name", "Felix");
map.put("age", 70);

String myPattern = 
        "Hi %(emptyKey)s! My name is %(name)s %(name)s and I am %(age)s years old";
System.out.println(format(myPattern, map));

输出:

Hi null! My name is Felix Felix and I am 70 years old

如您所见,您可以多次使用相同的键(在我们的例子中name),如果您的地图不包含字符串模式中使用的键(如emptyKey),它将被替换为null.


上面的版本是为了让你设置数据类型s d等等,但如果你的数据总是会被字符串替换,那么你可以跳过String.format(sb.toString(), valuesList.toArray())所有的键并将所有的键替换为更早的值。

这是一个更简单的版本,它只接受具有<String,String>键值关系的映射。

static Pattern stringsPattern = Pattern.compile("%\\(([^)]+)\\)s\\b");

public static String formatStrings(String pattern, Map<String, String> map) {
    StringBuffer sb = new StringBuffer();
    Matcher m = stringsPattern.matcher(pattern);

    while (m.find()) {
        // we can't use null as replacement so we need to convert it to String
        // first. We can do it with String.valueOf method
        m.appendReplacement(sb, String.valueOf(map.get(m.group(1))));
    }
    m.appendTail(sb);

    return sb.toString();
}
于 2013-07-26T12:44:54.663 回答
1

你想要String.format方法。

String data  = "Hello, %s";
String updated = String.format(data, "Felix");
于 2013-07-26T03:03:29.480 回答
0

如果您想要更高级的技术,例如 i18n 支持,您可以使用高级消息格式功能

例如:在语言属性文件中,您添加属性“模板”,这是您的消息

template = At {2,time,short} on {2,date,long}, \
    we detected {1,number,integer} spaceships on \
    the planet {0}.

然后你可以格式化你的变量传递数组中的参数:

Object[] messageArguments = {
    "Mars",
    new Integer(7),
    new Date()
};

你这样称呼格式化程序:

MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);
formatter.applyPattern(messages.getString("template"));
String output = formatter.format(messageArguments);

详细示例在这里 http://docs.oracle.com/javase/tutorial/i18n/format/messageFormat.html

于 2013-07-26T03:18:16.090 回答
0

在这个用例下,您需要像velocity或freemarker这样的模板引擎来使用类似Map的数据结构来呈现字符串模板,Java中没有内置模块可以做到这一点。像这样(有速度):

public static void main(String[] args) {
    Context context = new VelocityContext();
    context.put("appid", "9876543d1");
    context.put("ds", "2013-09-11");
    StringWriter sw = new StringWriter();
    String template = "APPID is ${appid} and DS is ${ds}";
    Velocity.evaluate(context, sw, "velocity", template);
    System.out.println(sw.toString());
}
于 2013-10-23T04:10:10.927 回答