【发布时间】:2011-09-19 21:21:06
【问题描述】:
原始问题,但我如何格式化这样的字符串:
“第 {2} 步的第 {1} 步”
通过使用 Java 替换变量?在 C# 中这很容易。
【问题讨论】:
标签: java string string-formatting
原始问题,但我如何格式化这样的字符串:
“第 {2} 步的第 {1} 步”
通过使用 Java 替换变量?在 C# 中这很容易。
【问题讨论】:
标签: java string string-formatting
格式化字符串最常用的方法是使用这种静态方法,该方法自 Java 5 起就长期可用,并且有两个重载方法:
该方法易于使用,format 模式由底层formatter 定义。
String step1 = "one";
String step2 = "two";
// results in "Step one of two"
String string = String.format("Step %s of %s", step1, step2);
您可以传递Locale 以尊重语言和区域规范。有关详细信息,请参阅此答案:https://stackoverflow.com/a/6431949/3764965(感谢 Martin Törnwall)。
MessageFormat 类从 Java 的第一个版本开始可用,适用于国际化。在最简单的形式中,有一个用于格式化的静态方法:
String step1 = "one";
String step2 = "two";
// results in "Step one of two"
String string = MessageFormat.format("Step {0} of {1}", step1, step2);
请记住 MessageFormat 遵循不同于 String#format 的特定模式,请参阅其 JavaDoc 了解更多详细信息:MessageFormat - patterns。
可以使用Locale,但是,必须实例化类的对象并将其传递给构造函数,因为上面的静态方法使用具有默认语言环境的默认构造函数。有关更多信息,请参阅此答案:https://stackoverflow.com/a/6432100/3764965(归功于ataylor)。
有很多方法可以使用外部库来格式化字符串。如果仅出于字符串格式化的目的导入库,它们几乎没有任何好处。几个例子:
StringSubstitutor,其 JavaDoc 中的示例。FormattedText,示例here。请随意添加更多内容,但我找不到进一步扩展此部分的理由。
从 Java 15 开始,有一个名为 String#formatted(Object... args) 的新实例方法。
内部实现同String#format(String format, Object... args)。
使用此字符串作为格式字符串和提供的参数的格式。
String step1 = "one";
String step2 = "two";
// results in "Step one of two"
String string = "Step %s of %s".formatted(step1, step2);
优点:区别在于方法不是static,而格式化模式是一个字符串本身,根据@987654355创建一个新的@。这允许链接首先构建格式本身。
缺点:Locale没有重载方法,所以使用默认的。如果您需要使用自定义Locale,则必须坚持使用String#format(Locale l, String format, Object... args)。
【讨论】:
Apache Commons StringSubstitutor 提供了一种简单易读的方式来使用命名变量格式化 Strings。
import org.apache.commons.text.StringSubstitutor;
// ...
Map<String, String> values = new HashMap<>();
values.put("animal", "quick brown fox");
values.put("target", "lazy dog");
StringSubstitutor sub = new StringSubstitutor(values);
String result = sub.replace("The ${animal} jumped over the ${target}.");
// "The quick brown fox jumped over the lazy dog."
该类支持为变量提供默认值。
String result = sub.replace("The number is ${undefined.property:-42}.");
// "The number is 42."
要使用递归变量替换,请调用setEnableSubstitutionInVariables(true);。
Map<String, String> values = new HashMap<>();
values.put("b", "c");
values.put("ac", "Test");
StringSubstitutor sub = new StringSubstitutor(values);
sub.setEnableSubstitutionInVariables(true);
String result = sub.replace("${a${b}}");
// "Test"
【讨论】:
来自 Apache Commons Text 的 org.apache.commons.text.StringSubstitutor 帮助器类提供命名变量替换
Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String resolved = new StringSubstitutor(valuesMap).replace("The ${animal} jumped over the ${target}.");
System.out.println(resolved); // The quick brown fox jumped over the lazy dog.
【讨论】:
我写了这个函数,它做了正确的事情。用同名变量的值插入以$ 开头的单词。
private static String interpol1(String x){
Field[] ffield = Main.class.getDeclaredFields();
String[] test = x.split(" ") ;
for (String v : test ) {
for ( Field n: ffield ) {
if(v.startsWith("$") && ( n.getName().equals(v.substring(1)) )){
try {
x = x.replace("$" + v.substring(1), String.valueOf( n.get(null)));
}catch (Exception e){
System.out.println("");
}
}
}
}
return x;
}
【讨论】:
看看String.format。但是请注意,它采用类似于 C 的 printf 系列函数的格式说明符——例如:
String.format("Hello %s, %d", "world", 42);
将返回“Hello world,42”。在了解格式说明符时,您可能会发现 this 很有帮助。 Andy Thomas-Cramer 很友好地在下面的评论中留下了this 链接,这似乎指向了官方规范。最常用的是:
这与 C# 完全不同,C# 使用带有可选格式说明符的位置引用。 这意味着你不能做这样的事情:
String.format("The {0} is repeated again: {0}", "word");
... 实际上没有重复传递给 printf/format 的参数。(请参阅下面的 Scrum Meister 评论)
如果您只想直接打印结果,您可以根据自己的喜好找到 System.out.printf (PrintStream.printf)。
【讨论】:
String.format 也可以取数字位置:String.format("%2$s %1$s", "foo", "bar"); 将输出bar foo
"Hello %s, %d".formatted("world", 42)
这个解决方案对我有用。我需要为 REST 客户端动态创建 url,所以我创建了这个方法,所以你只需要像这样传递 restURL
/customer/{0}/user/{1}/order
并根据需要添加尽可能多的参数:
public String createURL (String restURL, Object ... params) {
return new MessageFormat(restURL).format(params);
}
你只需要像这样调用这个方法:
createURL("/customer/{0}/user/{1}/order", 123, 321);
输出
"/customer/123/user/321/order"
【讨论】:
public class StringFormat {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("================================");
for(int i=0;i<3;i++){
String s1=sc.next();
int x=sc.nextInt();
System.out.println(String.format("%-15s%03d",s1,x));
}
System.out.println("================================");
}
}
前哨 "================================="
ved15space123 ved15space123 ved15space123 "=================================
Java 解决方案
“-”用于左缩进
“15”使字符串占用的最小长度为 15
我已经为它写了我的简单方法:
public class SomeCommons {
/** Message Format like 'Some String {0} / {1}' with arguments */
public static String msgFormat(String s, Object... args) {
return new MessageFormat(s).format(args);
}
}
所以你可以把它用作:
SomeCommons.msfgFormat("Step {1} of {2}", 1 , "two");
【讨论】:
如果选择不使用 String.format,另一个选项是 + 二元运算符
String str = "Step " + a + " of " + b;
这相当于
new StringBuilder("Step ").append(String.valueOf(1)).append(" of ").append(String.valueOf(2));
使用哪个是您的选择。 StringBuilder 更快,但速度差异很小。我更喜欢使用 + 运算符(它执行 StringBuilder.append(String.valueOf(X))) 并发现它更易于阅读。
【讨论】:
+ 运算符的工作原理。 2)你的解释甚至不准确。 + 相当于使用StringBuilder,而不是String.concat。 (Way too much info on this.)
除了String.format,还可以看看java.text.MessageFormat。格式不太简洁,更接近您提供的 C# 示例,您也可以使用它进行解析。
例如:
int someNumber = 42;
String someString = "foobar";
Object[] args = {new Long(someNumber), someString};
MessageFormat fmt = new MessageFormat("String is \"{1}\", number is {0}.");
System.out.println(fmt.format(args));
一个更好的示例利用 Java 1.5 中的可变参数和自动装箱改进,并将上述内容变成单行:
MessageFormat.format("String is \"{1}\", number is {0}.", 42, "foobar");
MessageFormat 更适合使用选择修饰符进行 i18nized 复数。要指定在变量为 1 时正确使用单数形式而在其他情况下使用复数形式的消息,您可以执行以下操作:
String formatString = "there were {0} {0,choice,0#objects|1#object|1<objects}";
MessageFormat fmt = new MessageFormat(formatString);
fmt.format(new Object[] { new Long(numberOfObjects) });
【讨论】:
MessageFormat.format("Number {0}", 1234)); 取决于默认语言环境可以生成 Number 1,234 而不是 Number 1234。
{0} it ll take firstname 时,当{1} then lastname 时,就像这样。有没有可能像{0,choice,0.getFirstName()} 或类似的东西?