有没有办法分析传递给String.format(...)的模式

时间:2014-06-25 13:31:29

标签: java string format formatter

我想分析最终传递给

的模式
String.format(String pattern, Object... args)

让我们考虑一下模式

"Integer is %d, String is %s"

有没有办法可以解析这种模式来确定

  1. arg0将格式化为数字
  2. arg1将格式化为字符串
  3. 显然我可以使用正则表达式执行此操作,但是当在模式中指定索引等时,这会变得更加困难。例如,让我们考虑另一种模式

    "String is %2$s, Integer is %1$d"
    

    这里arg1在arg0之前指定,但是这两个模式对于相同的参数具有相同的格式化。

    我真的很想使用核心java类来解析模式并对其进行分析,但似乎所有方法都是私有的。在幕后,String.format()使用Formatter

    最终,我试图编写一个测试用例来验证我的各种语言翻译文件并发现冲突(例如,一种语言指定日期格式,另一种语言指定同一参数的数字格式)。

2 个答案:

答案 0 :(得分:0)

对于开源项目,您可以将自己的TestFormatter基于Formatter (source)的源。然后,在format()方法的切换情况下,请记住参数类型,如下所示:

代码:

argument = args[argumentIndex];

switch (conversion) {
    case 'b':
        argumentHashMap.put(new Integer(argumentIndex), Boolean.class);
        booleanFormat(argument, flags, width, precision, origConversion);
        break;
    case 's':
        argumentHashMap.put(new Integer(argumentIndex), String.class);              
        stringFormat(argument, flags, width, precision, origConversion);
        break;
    case 'd':
        argumentHashMap.put(new Integer(argumentIndex), Double.class);              
        decimalConversion(argument, flags, width, precision, origConversion);
        break;
    ...

我添加了argumentHashMap行。

答案 1 :(得分:0)

我最终通过借用java源代码中的正则表达式来解决我的问题。

public class MyTest {
    static class PlaceHolder {
        int index;
        String flags;
        Integer width;
        Integer precision;
        String type;
        String conversion;

        @Override
        public String toString() {
            return String.format("PlaceHolder[index=%s, conversion=%s, flags=%s, width=%s, precision=%s, type=%s]",
                    index, conversion, flags, width, precision, type);
        }
    }

    public List<PlaceHolder> getPlaceholders(String pattern) {
        // %[argument_index$][flags][width][.precision][t]conversion
        Pattern regex = Pattern.compile("%((\\d+)\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.(\\d+))?([tT])?([a-zA-Z%])");

        int nextImplicitIndex = 1;
        Matcher matcher = regex.matcher(pattern);

        List<PlaceHolder> placeholders = new ArrayList<PlaceHolder>();
        while (matcher.find()) {
            String sIndex = matcher.group(2);
            int index = sIndex == null ? nextImplicitIndex++ : Integer.parseInt(sIndex);
            String flags = matcher.group(3);
            String sWidth = matcher.group(4);
            String sPrecision = matcher.group(6);
            String type = matcher.group(7);
            String conversion = matcher.group(8);

            PlaceHolder placeholder = new PlaceHolder();
            placeholder.index = index;
            placeholder.flags = flags;
            placeholder.width = sWidth == null ? null : new Integer(sWidth);
            placeholder.precision = sPrecision == null ? null : new Integer(sPrecision);
            placeholder.type = type;
            placeholder.conversion = conversion;

            placeholders.add(placeholder);

        }
        return placeholders;
    }

    @Test
    public void testGetPlaceholders() {
        System.out.println(getPlaceholders("Integer is %d, String is %s"));
        System.out.println(getPlaceholders("String is %2$s, Integer is %1$d"));
        System.out.println(getPlaceholders("%,6.2f"));
        System.out.println(getPlaceholders("Today is %tB %te, %tY %n"));
    }
}

测试输出以下内容:

[PlaceHolder[index=1, conversion=d, flags=, width=null, precision=null, type=null], PlaceHolder[index=2, conversion=s, flags=, width=null, precision=null, type=null]]
[PlaceHolder[index=2, conversion=s, flags=, width=null, precision=null, type=null], PlaceHolder[index=1, conversion=d, flags=, width=null, precision=null, type=null]]
[PlaceHolder[index=1, conversion=f, flags=,, width=6, precision=2, type=null]]
[PlaceHolder[index=1, conversion=B, flags=, width=null, precision=null, type=t], PlaceHolder[index=2, conversion=e, flags=, width=null, precision=null, type=t], PlaceHolder[index=3, conversion=Y, flags=, width=null, precision=null, type=t], PlaceHolder[index=4, conversion=n, flags=, width=null, precision=null, type=null]]