在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中是否可能(希望没有外部库)?
当前回答
另一个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.
其他回答
我最终得到了下一个解决方案: 使用substitute()方法创建类templatessubstitute,并使用它格式化输出 然后创建一个字符串模板,并用值填充它
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String template = "WRR = {WRR}, SRR = {SRR}\n" +
"char_F1 = {char_F1}, word_F1 = {word_F1}\n";
Map<String, Object> values = new HashMap<>();
values.put("WRR", 99.9);
values.put("SRR", 99.8);
values.put("char_F1", 80);
values.put("word_F1", 70);
String message = TemplateSubstitutor.substitute(values, template);
System.out.println(message);
}
}
class TemplateSubstitutor {
public static String substitute(Map<String, Object> map, String input_str) {
String output_str = input_str;
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
output_str = output_str.replace("{" + key + "}", String.valueOf(value));
}
return output_str;
}
}
在编写本文时,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();
}
}
我的答案是:
a)尽可能使用StringBuilder
b)保持“占位符”的位置(以任何形式:整数是最好的,特殊字符如dollar宏等),然后使用StringBuilder.insert()(参数的几个版本)。
当StringBuilder内部转换为String时,使用外部库似乎有些过度,而且我认为会显著降低性能。
不幸的是,答案是否定的。然而,你可以非常接近一个合理的语法:
"""
You are $compliment!
"""
.replace('$compliment', 'awesome');
它比String更具可读性和可预测性。至少是格式!
你可以在字符串助手类上有这样的东西
/**
* An interpreter for strings with named placeholders.
*
* For example given the string "hello %(myName)" and the map <code>
* <p>Map<String, Object> map = new HashMap<String, Object>();</p>
* <p>map.put("myName", "world");</p>
* </code>
*
* the call {@code format("hello %(myName)", map)} returns "hello world"
*
* It replaces every occurrence of a named placeholder with its given value
* in the map. If there is a named place holder which is not found in the
* map then the string will retain that placeholder. Likewise, if there is
* an entry in the map that does not have its respective placeholder, it is
* ignored.
*
* @param str
* string to format
* @param values
* to replace
* @return formatted string
*/
public static String format(String str, Map<String, Object> values) {
StringBuilder builder = new StringBuilder(str);
for (Entry<String, Object> entry : values.entrySet()) {
int start;
String pattern = "%(" + entry.getKey() + ")";
String value = entry.getValue().toString();
// Replace every occurence of %(key) with value
while ((start = builder.indexOf(pattern)) != -1) {
builder.replace(start, start + pattern.length(), value);
}
}
return builder.toString();
}