Можно ли как-то использовать CompactDecimalFormat для форматирования денежных значений?

Я пытаюсь использовать CompactDecimalFormat ICU4J для форматирования таких значений, как «12345,67», в «12 тысяч долларов». Я не вижу, как включить валюту в форматирование:

CompactDecimalFormat cdFormat =
   CompactDecimalFormat.getInstance(Locale.US, CompactStyle.SHORT);
Currency currency = Currency.getInstance(Locale.US);
CurrencyAmount amount = new CurrencyAmount(12345.67, currency);
System.out.println(cdFormat.format(amount));

В результате получается распечатка

12K

Как я могу заставить его учитывать валюту и вместо этого выводить «12 тысяч долларов» (и другие локали + соответствующие компактные значения валюты в других локалях и валютах)?


person jwl    schedule 03.02.2014    source источник


Ответы (2)


Вы можете использовать валюту.getSymbol().

person Guy Bouallet    schedule 03.02.2014
comment
Очевидно, я могу это сделать. Но как я могу получить средство форматирования, которое будет делать это автоматически, помещая символ или код валюты в нужное место для данной комбинации локали + валюты? - person jwl; 03.02.2014

Я обнаружил, что для вывода префикса валюты мы можем использовать NumberFormat:

NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.US);        
Currency currency = Currency.getInstance(Locale.US);
CurrencyAmount amount = new CurrencyAmount(12345.67, currency);
System.out.println(numberFormat.format(amount));

Это напечатает 12 345,67 долларов.

Однако здесь мы теряем компактное форматирование. Так что у меня не было выбора, кроме как погрузиться в исходный код ICU4J (52.1). После отладки выясняется, что CompactDecimalFormat.java основан на NumberFormat, но используется следующим образом:

lig:145    DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(locale);

Кроме того, там есть закомментированный блок кода TODO для исправления форматирования валюты. Итак, я делаю вывод, что последняя версия библиотеки не поддерживает стандартное компактное форматирование валюты.

Я пошел дальше и попробовал простой патч для файла CompactDecimalFormat.java. Я добавил следующие методы:

public static CompactDecimalFormat getInstance(Locale locale, CompactStyle style, int formatNumberStyle) {
    return new CompactDecimalFormat(ULocale.forLocale(locale), style,formatNumberStyle);
}    
CompactDecimalFormat(ULocale locale, CompactStyle style,int numberFormatStyle) {
    this.pluralRules = PluralRules.forLocale(locale);
    DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(locale,numberFormatStyle);
    CompactDecimalDataCache.Data data = getData(locale, style);
    this.units = data.units;
    this.divisor = data.divisors;
    pluralToCurrencyAffixes = null;
    finishInit(style, format.toPattern(), format.getDecimalFormatSymbols());
}

Затем я изменил ваш код следующим образом:

    CompactDecimalFormat cdFormat = CompactDecimalFormat.getInstance(
            Locale.US, CompactStyle.SHORT,NumberFormat.CURRENCYSTYLE);
    Currency currency = Currency.getInstance(Locale.US);
    CurrencyAmount amount = new CurrencyAmount(12345.67, currency);
    System.out.println(cdFormat.format(amount));

и я наконец смог увидеть ожидаемое: 12 тысяч долларов.

Я надеюсь, что это решит вашу проблему.

person Guy Bouallet    schedule 03.02.2014
comment
сообщить об ошибке? поставить патч? - person Steven R. Loomis; 07.02.2014
comment
Хороший хак. Но я не могу изменить библиотеку - person jwl; 07.02.2014
comment
@jlarson: нет необходимости изменять банку библиотеки. Просто скопируйте измененный CompactDecimalFormat в свои исходники, сохранив расположение пакета, и убедитесь, что он загружен первым загрузчиком классов. Конечно, это обходной путь, и я согласен со Стивеном, что нужно что-то делать напрямую с разработчиками. Не стесняйтесь отправлять изменения или получать их отзывы о них. - person Guy Bouallet; 08.02.2014
comment
@GuyBouallet Верно. (и я один из разработчиков ICU) - person Steven R. Loomis; 15.02.2014