在 Python 中,我们可以很容易地做到这一点:
data = {'name':'Felix'}
s = 'Hello, %(name)s' % data
s
'Hello, Felix'
Java中是否有类似的方法来实现相同的东西?
PS:对不起,不清楚的问题。用例是:我们有一个存储键值的映射,模板只需要在映射中指定一个键,那么键的值就会在模板中键所在的位置。
AFAIK 你可以用String#format
这个:
String name = "Felix";
String s = String.format("Hello, %s", name);
System.out.println(s);
这将打印
Hello, Felix
有关如何使用格式的更多信息String#format
可以在java.util.Formatter
语法中找到
如果您只想用字符串替换字符串,那么我答案第二部分的代码会更好
Java Formatter类不支持%(key)s
表单,但您可以使用%index$s
where 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();
}
你想要String.format方法。
String data = "Hello, %s";
String updated = String.format(data, "Felix");
如果您想要更高级的技术,例如 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
在这个用例下,您需要像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());
}