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

时间:2015-06-26 08:56:04

标签: java

我正在尝试使用MessageFormat类在java中格式化String。 String包含位置字段,但只有在我提供字段编号时才有效。例如

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)

有没有办法(任何其他类或库),它可以处理像python那样的自动和手动字段编号?

In [3]: print "{} {}".format("Hi", "Java")
Hi Java

In [4]: print "{0} {1}".format("Hi", "Java")
Hi Java

5 个答案:

答案 0 :(得分:3)

您可以执行以下操作:

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

它首先用{}替换%s,然后将每个%s替换为您提供的String数组中的相应值作为format方法的参数。

请注意,由于format接受Object... args作为第二个参数,您可以写:

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

答案 1 :(得分:2)

听起来像String.format()就是你想要的。

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

答案 2 :(得分:1)

我使用slf4j进行日志记录,这使您能够记录如下字符串:

LoggerFactory.getLogger("name").debug("{} {}", "Hello", "World");

刚看了一下源代码,看看用于格式化字符串的内容,它使用了这个类:

org.slf4j.helpers.MessageFormatter

这里有3种方法可供选择。 1替换单个对象:

MessageFormatter.format(String message, Object arg);

替换2个物体:

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();
}

答案 3 :(得分:1)

添加到@JohnH答案,String.format可以自动和手动字段索引来格式化String。

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

Reference Doc

它不符合"{1} {2}"的人体工程学,但可以完成工作。

答案 4 :(得分:1)

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

除了使用索引参数手动准备字符串之外,Ben Greens聪明的想法对于使用非索引参数进行日志记录时使用sfl4j的每个人都很有用。

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

所以我编写了Ben的解决方案的扩展版本,该解决方案利用了所有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);