这是一个基础问题,但我应该如何使用Java格式化字符串,例如:
"第{1}步,共{2}步"
在C#中很容易实现。
这是一个基础问题,但我应该如何使用Java格式化字符串,例如:
"第{1}步,共{2}步"
在C#中很容易实现。
请查看String.format。但请注意,它使用与C的printf函数族类似的格式说明符,例如:
String.format("Hello %s, %d", "world", 42);
将返回“Hello world, 42”。当学习格式说明符时,您可能会发现这个链接有所帮助。Andy Thomas-Cramer在下面的评论中留下了这个链接,似乎指向官方规范。最常用的是:
这与使用具有可选格式说明符的位置引用的C#截然不同。这意味着您无法执行以下操作:
String.format("The {0} is repeated again: {0}", "word");
如果你只想直接输出结果,你可能会发现System.out.printf(PrintStream.printf)很适合你。
(请参见Scrum Meister的下方评论)
String.format
可以使用数字位置:String.format("%2$s %1$s", "foo", "bar");
将输出 bar foo
。 - The Scrum Meister除了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
对于使用选择修饰符进行国际化复数形式的处理要更加方便。为了指定一个正确使用单数形式当变量为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
。 - pavel_kazlou{0}
时它将获取名字,当{1}
时获取姓氏,以此类推。是否可以像这样使用{0,choice,0.getFirstName()}
或类似的方式? - user3145373 ツMessageFormat
比 String.format
慢了数倍,除非你打算永生,否则应避免使用它。这不应该是被接受的答案。 - ccpizzaMessageFormat
可能会慢一些,但这取决于它的使用方式是否重要,而且这是对原始问题更好的答案。 - M_M使用此静态方法是格式化字符串的最常见方式,从Java 5以来已经存在,并且有两个重载方法:
该方法易于使用,其format
模式由底层格式化器定义。
String step1 = "one";
String step2 = "two";
// results in "Step one of two"
String string = String.format("Step %s of %s", step1, step2);
Locale
来遵循语言和区域规范。有关更多信息,请参见此答案:https://dev59.com/u2w15IYBdhLWcg3wu-I9#6431949(感谢Martin Törnwall)。
MessageFormat
类已经可用,并且适用于国际化。在最简单的形式中,有一个静态方法进行格式化:
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://dev59.com/u2w15IYBdhLWcg3wu-I9#6432100(感谢ataylor)。StringSubstitutor
,在其 JavaDoc 中提供了示例。
- Cactoos:FormattedText
,此处提供了示例。
- 有趣的是,Guava 不打算添加格式化或模板功能:#1142。
- ...和其他自定义实现。
欢迎添加更多,但我认为没有理由进一步扩展此部分。
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
方法不同,该方法的格式化模式是一个字符串本身,基于 args
创建一个新的字符串。这允许链式组合来首先构建格式本身。
缺点:没有使用 Locale
的重载方法,因此默认使用。如果需要使用自定义的 Locale
,则必须使用 String#format(Locale l, String format, Object... args)
。请注意保留 HTML 标签。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
。(此处提供的信息过多。) - Søren Løvborgpublic 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.msgFormat("Step {1} of {2}", 1 , "two");
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
String name = "Joan";
String info = STR."My name is \{name}";
assert info.equals("My name is Joan"); // true
String query = "SELECT * FROM Person p WHERE p.last_name = '" + name + "'";
ResultSet rs = conn.createStatement().executeQuery(query);
但是这个变种(来自JEP 430)可以防止SQL注入:
PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
ResultSet rs = ps.executeQuery();
/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);
The output
"/customer/123/user/321/order"
Java有java.util.Formatter
,它在String
格式化方法中被内部使用。它非常强大,尽管使用起来更加复杂。以下是一个指南,根据您的Java版本,您应该使用什么:
Java 15+
// Sequential string arguments
"foo %s baz %s".formatted("bar", "foobar");
// Indexed string arguments
"foo %1$s baz %2$s".formatted("bar", "foobar");
任何早于Java 15的版本:
// Sequential string arguments
String.format("foo %s baz %s", "bar", "foobar");
// Indexed string arguments
String.format("foo %1$s baz %2$s", "bar", "foobar");
早于Java 5:
MessageFormat.format("foo {0} baz {1}", "bar", "foo");
最后一个例子是为了完整性而提供的,但你不应该使用它,因为它是所有选项中最慢的。
Apache Commons Text的StringSubstitutor
提供了一种简单易读的方式来使用命名变量格式化String
。
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"