MessageFormat中的嵌套选择子句?

时间:2014-04-07 12:55:30

标签: java messageformat

我正在尝试用java.text.MessageFormat:

做一个简单的逻辑
MessageFormat cf = new MessageFormat(
"{0,choice, 1<hello|5<{1,choice,1<more than one|4<more than four}}");

 Object[] array = {3, 1};
 System.out.println(cf.format(array));

使用单词:如果第一个参数大于1,则打印“hello”,如果大于5则打印第二个参数大于1打印“多于一个”如果第二个参数大于4打印“四个以上“。

我发现没有人说这是不可能的,但我得到了IllegalArgumentException:

Choice Pattern incorrect: 1<hello|5<{1,choice,1<more than one|4<more than four}

我有办法做到这一点吗?谢谢!

整个堆栈跟踪:

Exception in thread "main" java.lang.IllegalArgumentException: Choice Pattern incorrect:  1<hello|5<{1,choice,1<more than one|4<more than four}
at java.text.MessageFormat.makeFormat(Unknown Source)
at java.text.MessageFormat.applyPattern(Unknown Source)
at java.text.MessageFormat.<init>(Unknown Source)
at test.Test5.main(Test5.java:18)
Caused by: java.lang.IllegalArgumentException
    at java.text.ChoiceFormat.applyPattern(Unknown Source)
    at java.text.ChoiceFormat.<init>(Unknown Source)
    ... 4 more

2 个答案:

答案 0 :(得分:9)

如果您编写这样的模式,ChoiceFormat无法解析格式,因为它无法知道格式分隔符(|)之类的控制字符是用于内部格式还是外部格式格式。但是如果你引用嵌套的格式,你可以告诉解析器引用的文本不包含它应该解析的任何控制字符。然后ChoiceFormat将返回包含其他ChoiceFormat模式的文字。

如果MessageFormat类应用ChoiceFormat,它会再次将结果解析为MessageFormat以处理其他参数处理,然后处理内部ChoiceFormat

因此,如果你编写这样的模式代码就可以了:

MessageFormat cf = new MessageFormat(
    "{0,choice, 1<hello|5<'{1,choice,1<more than one|4<more than four}'}");

Object[] array = {3, 1};
System.out.println(cf.format(array));

答案 1 :(得分:1)

如@Reboot所述,与这些类混淆的部分原因是ChoiceFormat在这里特别MessageFormat.subformat()被对待:

        subFormatter = formats[i];
        if (subFormatter instanceof ChoiceFormat) {
            arg = formats[i].format(obj);
            if (arg.indexOf('{') >= 0) {
                subFormatter = new MessageFormat(arg, locale);
                obj = arguments;
                arg = null;
            }
        }

此骇客是允许MessageFormat包含ChoiceFormat本身包含MessageFormat的原因:

new ChoiceFormat("0#none|1#one|1<{0}").format(3);                                // "{0}"
new MessageFormat("{0,choice,0#none|1#one|1<{0}}").format(new Object[] { 3 });   // "3"

当然,在特殊情况下,嵌套在ChoiceFormat中的MessageFormat可能包含嵌套的ChoiceFormat,只要您正确地转义/引用即可。

这些类在语法/解析方面非常繁琐。与Java或bash的解析/转义/引用是“嵌套”不同,此处的解析是“渴望” ...但是可以。

我写了一些课程来帮助消除这种疯狂。这些课程不会尝试重新发明轮子。它们只是使已经存在的基础结构和嵌套可见。但是它们允许您绕过所有引号问题,并且它们支持任意嵌套深度。

在我自己的项目中,我已将它们连接为XML。这使我可以定义如下消息:

<message key="how.many.items">
    <text>There </text>
    <choice argnum="0">
        <option limit="0">
            <text>are no items</text>
        </option>
        <option limit="1">
            <text>is one item</text>
        </option>
        <option limit="1&lt;">
            <text>are </text>
            <choice argnum="0">
                <option limit="0">
                    <number argnum="0"/>
                </option>
                <option limit="100">
                    <text>way too many</text>
                </option>
            </choice>
            <text>items</text>
        </option>
    </choice>
    <text>.</text>
</message>

有关详细信息,请参见MessageFmt