在Python中,格式化字符串时,我可以按名称而不是按位置填充占位符,如下所示:
print "There's an incorrect value '%(value)s' in column # %(column)d" % \
{ 'value': x, 'column': y }
我想知道这在Java中是否可能(希望没有外部库)?
在Python中,格式化字符串时,我可以按名称而不是按位置填充占位符,如下所示:
print "There's an incorrect value '%(value)s' in column # %(column)d" % \
{ 'value': x, 'column': y }
我想知道这在Java中是否可能(希望没有外部库)?
当前回答
在编写本文时,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();
}
}
其他回答
另一个Apache Common StringSubstitutor的简单命名占位符的例子。
String template = "Welcome to {theWorld}. My name is {myName}.";
Map<String, String> values = new HashMap<>();
values.put("theWorld", "Stackoverflow");
values.put("myName", "Thanos");
String message = StringSubstitutor.replace(template, values, "{", "}");
System.out.println(message);
// Welcome to Stackoverflow. My name is Thanos.
您应该看看官方的ICU4J库。它提供了一个类似于JDK的MessageFormat类,但前者支持命名占位符。
与本页提供的其他解决方案不同。ICU4j是ICU项目的一部分,由IBM维护并定期更新。此外,它还支持高级用例,如多元化等。
下面是一个代码示例:
MessageFormat messageFormat =
new MessageFormat("Publication written by {author}.");
Map<String, String> args = Map.of("author", "John Doe");
System.out.println(messageFormat.format(args));
截至2022年,最新的解决方案是Apache Commons Text StringSubstitutor
医生说:
// Build map
Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target} ${undefined.number:-1234567890} times.";
// Build StringSubstitutor
StringSubstitutor sub = new StringSubstitutor(valuesMap);
// Replace
String resolvedString = sub.replace(templateString)
;
不完全是,但你可以使用MessageFormat多次引用一个值:
MessageFormat.format("There's an incorrect value \"{0}\" in column # {1}", x, y);
上面的事情也可以用string .format()来完成,但是如果你需要构建复杂的表达式,我发现messageFormat语法更干净,而且你不需要关心你放入字符串中的对象的类型
我试了一下
public static void main(String[] args)
{
String rowString = "replace the value ${var1} with ${var2}";
Map<String,String> mappedValues = new HashMap<>();
mappedValues.put("var1", "Value 1");
mappedValues.put("var2", "Value 2");
System.out.println(replaceOccurence(rowString, mappedValues));
}
private static String replaceOccurence(String baseStr ,Map<String,String> mappedValues)
{
for(String key :mappedValues.keySet())
{
baseStr = baseStr.replace("${"+key+"}", mappedValues.get(key));
}
return baseStr;
}