Java 字符串格式中的自动字段编号

Java 字符串格式中的自动字段编号,java,Java,我正在尝试使用MessageFormatclass在java中格式化字符串。字符串包含位置字段,但仅当我提供字段编号时才起作用。例如 MessageFormat.format(“{0}{1}”,“Hi”,“Java”) MessageFormat.format(“{}{}”,“Hi”,“Java”) Exception in thread "main" java.lang.IllegalArgumentException: can't parse argument number: at

我正在尝试使用
MessageFormat
class在java中格式化字符串。字符串包含位置字段,但仅当我提供字段编号时才起作用。例如

MessageFormat.format(“{0}{1}”,“Hi”,“Java”)

MessageFormat.format(“{}{}”,“Hi”,“Java”)

Exception in thread "main" java.lang.IllegalArgumentException: can't parse argument number: 
    at java.text.MessageFormat.makeFormat(MessageFormat.java:1429)
    at java.text.MessageFormat.applyPattern(MessageFormat.java:479)
    at java.text.MessageFormat.<init>(MessageFormat.java:362)
    at java.text.MessageFormat.format(MessageFormat.java:840)
    at controller.App.main(App.java:11)
Caused by: java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:592)
    at java.lang.Integer.parseInt(Integer.java:615)
    at java.text.MessageFormat.makeFormat(MessageFormat.java:1427)
听起来这就是你要找的

String foo = String.format("%s %s", "Hi", "Java")
StringBuffer bar = new StringBuffer(foo);

您可以执行以下黑客操作:

String.format("{} {}".replace("{}", "%s"), new String[]{"Hi", "Java"}));
它首先将
{}
替换为
%s
,然后将每个
%s
替换为作为方法参数提供的字符串数组中的相应值

请注意,由于
格式
接受
对象。。。args
作为第二个参数,您可以编写:

String.format("{} {}".replace("{}", "%s"), "Hi", "Java");

我使用slf4j进行日志记录,这样可以记录如下字符串:

LoggerFactory.getLogger("name").debug("{} {}", "Hello", "World");
只需看一看源代码,就知道它是如何格式化字符串的,它使用了以下类:

org.slf4j.helpers.MessageFormatter
这里有3种方法。1替换单个对象时:

MessageFormatter.format(String message, Object arg);
一个替换为两个对象:

MessageFormatter.format(String message, Object arg1, Object arg2);
其中一个用于替换对象数组:

MessageFormatter.arrayFormat(String message, Object[] argArray);
它们都返回类型为
FormattingTuple
的对象。要从对象获取格式化字符串,应调用
FormattingTuple.getMessage()

要与手动字段编号一起使用,请查看以下方法:

public String formatString(String original, Object... replacements) {
    String stringToReturn = original;
    for (int i = 0; i < replacements.length; i++) {
        stringToReturn = stringToReturn.replaceAll("\\{" + i + "\\}", replacements[i].toString());
    }
    return MessageFormatter.arrayFormat(stringToReturn, replacements).getMessage();
}
公共字符串格式字符串(字符串原始、对象…替换){
字符串stringToReturn=原始字符串;
for(int i=0;i
添加到@JohnH answer,String.format可以为格式化字符串执行自动和手动字段索引

String.format("%s %s", "Hi", "Java")
String.format("%1$s %2$s %1$s", "Hi", "Java")


这比不上
“{1}{2}”
更符合人体工程学,但它完成了任务。

如果我被限制在Barunthakur这样的标准库中,我会使用Maroun Maroun发布的模式

Ben Greens聪明的想法对于使用非索引参数登录时使用sfl4j的每个人都很有用,此外,还可以使用索引参数手动准备字符串

我有一个缺点: 我现在可以使用索引参数和非索引参数,但无法使用java.text.MessageFormat.format()中的FormatType和FormatStyle选项,例如{0,number,currency}

因此,我制定了本解决方案的扩展版本,它利用了所有3种变体

import org.slf4j.helpers.MessageFormatter;
import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public static String format(String original, Object... replacements)
{
    if (Pattern.matches(".*\\{\\d+,.+,.+\\}.*", original))
    {
        return MessageFormat.format(original, replacements);
    }
    else
    {
        String r = "\\{\\d\\}";

        if(original.matches(".*" + r + ".*"))
        {
            Pattern p = Pattern.compile(r);
            Matcher m = p.matcher(original);
            StringBuffer b = null;
            int i = 0;

            while(m.find())
            {
                if(b == null) b = new StringBuffer();
                m.appendReplacement(b, replacements[i].toString());
                i++;
            }
            m.appendTail(b);
            return (i > 0) ? b.toString() : null;
        }
        else
        {
            return MessageFormatter.arrayFormat(original, replacements).getMessage();
        }
    }
}
单元测试:

String expected = "pink is a disgusting color";
String actual = StringHelpers.format("{0} is a disgusting {1}", "pink", "color");
assertEquals(expected, actual);

expected = "01-02-2017 was a rather meh day";
actual = StringHelpers.format("{0,date,MM-dd-YYYY} was a rather {1} day", new Date(117,0,2), "meh");
assertEquals(expected, actual);

expected = "One Person expects the danish inquisition";
actual = StringHelpers.format("{} expects the {} inquisition", "One Person", "danish");
assertEquals(expected, actual);

如果您不想提供索引,那么请使用
String.format
。是的,我可以这样做,但有一个用例,我可以获得带或不带索引的字符串。是的,这将起作用,但不是我想要的。此外,这对参数的位置索引也没有帮助。@baruntshakur您必须检查需要使用哪个版本。请为此尝试一个正则表达式。
System.out.println(MessageFormatter.format(“{1}{2}{1}”,“hi”,“java”).getMessage()
输出
{1}{2}{1}
。您的问题表明您希望在不指定位置字段的情况下执行此操作<代码>System.out.println(MessageFormatter.format(“{}{}”,“hi”,“java”).getMessage())
outputs
hi java
No.“它可以处理自动和手动字段编号”刚刚用我编写的一个快速方法编辑了我的答案,以处理这两种情况。是的,这可以工作,但这是一个解决方法,我想要的是一个标准库或做它的东西。
String expected = "pink is a disgusting color";
String actual = StringHelpers.format("{0} is a disgusting {1}", "pink", "color");
assertEquals(expected, actual);

expected = "01-02-2017 was a rather meh day";
actual = StringHelpers.format("{0,date,MM-dd-YYYY} was a rather {1} day", new Date(117,0,2), "meh");
assertEquals(expected, actual);

expected = "One Person expects the danish inquisition";
actual = StringHelpers.format("{} expects the {} inquisition", "One Person", "danish");
assertEquals(expected, actual);