string格式的命名占位符

在Python中,格式化string时,我可以按名称而不是位置来填充占位符,如下所示:

print "There's an incorrect value '%(value)s' in column # %(column)d" % \ { 'value': x, 'column': y } 

我想知道这是否可能在Java(希望没有外部库)? 提前致谢。

雅加达公共朗的StrSubstitutor朗是一个轻量级的方式做到这一点,你的价值观已经正确格式化。

http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/text/StrSubstitutor.html

 Map<String, String> values = new HashMap<String, String>(); values.put("value", x); values.put("column", y); StrSubstitutor sub = new StrSubstitutor(values, "%(", ")"); String result = sub.replace("There's an incorrect value '%(value)' in column # %(column)"); 

以上结果是:

“#2列中有一个不正确的值”1“

使用Maven时,可以将这个依赖添加到你的pom.xml中:

 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> 

不太完美,但是您可以使用MessageFormat多次引用一个值:

 MessageFormat.format("There's an incorrect value \"{0}\" in column # {1}", x, y); 

上面的代码也可以用String.format()来完成,但是如果你需要构build复杂的expression式的话,我会发现messageFormat的语法更清晰,再加上你不需要关心你要放入string的对象的types

你可以使用StringTemplate库,它提供了你想要的和更多。

 import org.antlr.stringtemplate.*; final StringTemplate hello = new StringTemplate("Hello, $name$"); hello.setAttribute("name", "World"); System.out.println(hello.toString()); 

感谢你的帮助! 使用所有的线索,我已经编写了例程来完成我想要的function – 使用字典的类似python的string格式。 由于我是Java新手,任何提示都表示赞赏。

 public static String dictFormat(String format, Hashtable<String, Object> values) { StringBuilder convFormat = new StringBuilder(format); Enumeration<String> keys = values.keys(); ArrayList valueList = new ArrayList(); int currentPos = 1; while (keys.hasMoreElements()) { String key = keys.nextElement(), formatKey = "%(" + key + ")", formatPos = "%" + Integer.toString(currentPos) + "$"; int index = -1; while ((index = convFormat.indexOf(formatKey, index)) != -1) { convFormat.replace(index, index + formatKey.length(), formatPos); index += formatPos.length(); } valueList.add(values.get(key)); ++currentPos; } return String.format(convFormat.toString(), valueList.toArray()); } 

对于简单的情况,你可以简单地使用硬编码的stringreplace,不需要在那里的库:

  String url = "There's an incorrect value '%(value)' in column # %(column)"; url = url.replace("%(value)", x); url = url.replace("%(column)", y); 

这是一个古老的线程,但只是为了logging,你也可以使用Java 8风格,就像这样:

 public static String replaceParams(Map<String, String> hashMap, String template) { return hashMap.entrySet().stream().reduce(template, (s, e) -> s.replace("%(" + e.getKey() + ")", e.getValue()), (s, s2) -> s); } 

用法:

 public static void main(String[] args) { final HashMap<String, String> hashMap = new HashMap<String, String>() { { put("foo", "foo1"); put("bar", "bar1"); put("car", "BMW"); put("truck", "MAN"); } }; String res = replaceParams(hashMap, "This is '%(foo)' and '%(foo)', but also '%(bar)' '%(bar)' indeed."); System.out.println(res); System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(foo)', but also '%(bar)' '%(bar)' indeed.")); System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(truck)', but also '%(foo)' '%(bar)' + '%(truck)' indeed.")); } 

输出将是:

 This is 'foo1' and 'foo1', but also 'bar1' 'bar1' indeed. This is 'BMW' and 'foo1', but also 'bar1' 'bar1' indeed. This is 'BMW' and 'MAN', but also 'foo1' 'bar1' + 'MAN' indeed. 

你可以在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(); } 

基于我创build的MapBuilder类的答案 :

 public class MapBuilder { public static Map<String, Object> build(Object... data) { Map<String, Object> result = new LinkedHashMap<>(); if (data.length % 2 != 0) { throw new IllegalArgumentException("Odd number of arguments"); } String key = null; Integer step = -1; for (Object value : data) { step++; switch (step % 2) { case 0: if (value == null) { throw new IllegalArgumentException("Null key value"); } key = (String) value; continue; case 1: result.put(key, value); break; } } return result; } } 

然后我创buildStringFormatstring格式:

 public final class StringFormat { public static String format(String format, Object... args) { Map<String, Object> values = MapBuilder.build(args); for (Map.Entry<String, Object> entry : values.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); format = format.replace("$" + key, value.toString()); } return format; } } 

你可以这样使用:

 String bookingDate = StringFormat.format("From $startDate to $endDate"), "$startDate", formattedStartDate, "$endDate", formattedEndDate ); 

我的答案是:

a)尽可能使用StringBuilder

b)保留(以任何forms:整数是最好的,特殊字符如美元macros等)的位置“占位符”,然后使用StringBuilder.insert() (参数的几个版本)。

当使用外部库似乎矫枉过正,当我们将StringBuilder内部转换为string时,我认为会降低性能。

我是一个小型图书馆的作者,

 Student student = new Student("Andrei", 30, "Male"); String studStr = template("#{id}\tName: #{st.getName}, Age: #{st.getAge}, Gender: #{st.getGender}") .arg("id", 10) .arg("st", student) .format(); System.out.println(studStr); 

或者你可以链接参数:

 String result = template("#{x} + #{y} = #{z}") .args("x", 5, "y", 10, "z", 15) .format(); System.out.println(result); // Output: "5 + 10 = 15" 

试试Freemarker ,模板库。

替代文字http://freemarker.orghttp://img.dovov.comoverview.png

 public static String format(String format, Map<String, Object> values) { StringBuilder formatter = new StringBuilder(format); List<Object> valueList = new ArrayList<Object>(); Matcher matcher = Pattern.compile("\\$\\{(\\w+)}").matcher(format); while (matcher.find()) { String key = matcher.group(1); String formatKey = String.format("${%s}", key); int index = formatter.indexOf(formatKey); if (index != -1) { formatter.replace(index, index + formatKey.length(), "%s"); valueList.add(values.get(key)); } } return String.format(formatter.toString(), valueList.toArray()); } 

例:

 String format = "My name is ${1}. ${0} ${1}."; Map<String, Object> values = new HashMap<String, Object>(); values.put("0", "James"); values.put("1", "Bond"); System.out.println(format(format, values)); // My name is Bond. James Bond.