有没有办法在 Java 中呈现像 'Hello, %(name)s' % 'name':'Felix' 这样的字符串?
Posted
技术标签:
【中文标题】有没有办法在 Java 中呈现像 \'Hello, %(name)s\' % \'name\':\'Felix\' 这样的字符串?【英文标题】:Is there a way to render a string like 'Hello, %(name)s' % 'name':'Felix' in Java?有没有办法在 Java 中呈现像 'Hello, %(name)s' % 'name':'Felix' 这样的字符串? 【发布时间】:2013-07-26 04:20:29 【问题描述】:在 Python 中我们可以轻松做到这一点:
data = 'name':'Felix'
s = 'Hello, %(name)s' % data
s
'Hello, Felix'
在 Java 中是否有类似的方式来实现相同的东西?
PS: 对不起,不清楚的问题。用例是:我们有一个存储键值的映射,模板只需要在映射中指定一个键,那么键的值就会在模板中键所在的位置。
【问题讨论】:
【参考方案1】:在这个用例下,您需要像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());
【讨论】:
【参考方案2】:如果你只想用字符串替换字符串,那么我答案第二部分的代码会更好
Java Formatter 类不支持 %(key)s
形式,但您可以使用 %index$s
,其中索引从 1 开始计数,如本例所示
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();
【讨论】:
【参考方案3】:如果您想要更高级的技术,例如 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
【讨论】:
【参考方案4】:你想要String.format方法。
String data = "Hello, %s";
String updated = String.format(data, "Felix");
【讨论】:
【参考方案5】:AFAIK 您可以为此使用String#format
:
String name = "Felix";
String s = String.format("Hello, %s", name);
System.out.println(s);
这将打印出来
Hello, Felix
有关如何使用String#format
格式的更多信息,请访问java.util.Formatter
syntax
【讨论】:
以上是关于有没有办法在 Java 中呈现像 'Hello, %(name)s' % 'name':'Felix' 这样的字符串?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法以 HTML/XML 方式呈现 JAVA 组件/容器?
有没有办法像在 javascript 中一样在 C# 中交替使用单引号和双引号?
Hello Blazor:像ASP.NET WebForm一样写代码