2014-10-30 2 views
2

Я хотел бы использовать string.Format() форматировать некоторые BigDecimals как часть строки:Java string.Format() с HALF_EVEN округление

// Example: 
String getPrice(String pattern) 
{ 
    BigDecimal price = basePrice.multiply(BigDecimal.ONE.add(vatRate)); 
    BigDecimal priceInPence = price.multiply(new BigDecimal("100")); 
    BigDecimal annualPrice = price.multiply(new BigDecimal("365")); 

    return String.format(pattern, priceInPence, annualPrice); 
} 

String myPrice1 = getPrice("Your price is %1$.3fp/day (£2$.2f/year) including VAT"); 
// --> "Your price is 32.100p/day (£117.16/year) including VAT" 

String myPrice2 = getPrice("Around £%2$.0f annualy"); 
// --> "Around £117 annually" 

Однако docs для string.Format () говорят, что любое округление BigDecimals будет выполнено с округлением HALF_UP, тогда как мне нужно HALF_EVEN.

Я знаю, как вручную установить масштаб BigDecimals (Set specific precision of a BigDecimal) - но в этом случае я хочу иметь возможность использовать произвольную строку шаблона (включая нечисловые элементы шаблона), поэтому я не буду знать заранее какой масштаб использовать.

Мой вопрос таким образом:

  • можно установить режим округления, используемый string.Format()? OR

  • есть другой форматтер или библиотека, которая будет форматировать номера, как в моем примере?

+0

Взгляните на java.math.MathContext. Вы можете построить MathContext, используя java.math.RoundingMode (HALF_EVEN), а затем передать это конструктору BigDecimal или одному из методов умножения: 'multiply (BigDecimal multipicand, MathContext mc)' – mttdbrd

+0

@mttdbrd - извините, я должно быть ясно, мне нужна произвольная точность, основанная на шаблоне (см. мое редактирование выше). –

+0

http://stackoverflow.com/questions/9482889/set-specific-precision-of-a-bigdecimal и http://stackoverflow.com/questions/15352229/rounding-mode-with-bigdecimal-in-java – ComputerFellow

ответ

1

Действительно «твердый» совет, чтобы добавить 5000 строк дедвейтом кода для вашего проекта! Из того, что я вижу, Formatter не будет устанавливать масштаб, если он уже не настроен на то, что необходимо. Так помочь его, разобрать строку формата и установить масштаб:

public static String getPrice(String pattern) { 
    BigDecimal basePrice = new BigDecimal("23"); 
    BigDecimal vatRate = new BigDecimal("0.5"); 
    BigDecimal price = basePrice.multiply(BigDecimal.ONE.add(vatRate)); 
    BigDecimal priceInPence = price.multiply(new BigDecimal("100")); 
    BigDecimal annualPrice = price.multiply(new BigDecimal("365")); 

    Matcher matcher = Pattern.compile("%(\\d+)\\$.(\\d+)f").matcher(pattern); 

    while (matcher.find()) { 
     String index = matcher.group(1); 

     int scale = Integer.parseInt(matcher.group(2)); 

     if (index.equals("1")) 
      priceInPence = priceInPence.setScale(scale, RoundingMode.HALF_EVEN); 
     else if (index.equals("2")) 
      annualPrice = annualPrice.setScale(scale, RoundingMode.HALF_EVEN); 
    } 

    return String.format(pattern, priceInPence, annualPrice); 
} 

с этими числами я получаю этот выход:

Ваша цена включая 3450.000p/день (£ 12592,50/год) НДС

Около £ 12592 ежегодно

Так оно применяется правильное округление.

+0

Мне нравится этот подход. Это могло бы быть даже лучше, если бы оно было расширено, чтобы обработать случай, когда токен используется несколько раз с разными шкалами: getPrice («Около £% 2 $ .0f годовых (например,% 2.2f)»); –

0

Установите шкалу с режимом округления вам нравится, и включает в себя значение в строке формата как строку, используя BigDecimal#toString().

+0

Проблема в том, что я не знаю, какой масштаб использовать до выполнения: информация о точности находится в шаблоне String , –

3

Могу ли я установить режим округления, используемый String.format()?
Короткий ответ: нет.

есть ли другой форматтер или библиотека, которая форматировала числа, как в моем примере?
BigDecimal преобразуется внутренне через new MathContext(compPrec) или простое HALF_UP. Вы можете взять код java.util.Formatter из последней (или вашей предпочтительной) версии Java и изменить создание MathContext для использования HALF_EVEN. Это должно быть 10-15 минут работы. Но тогда вам нужен специальный метод, чтобы имитировать String.format:

public static String format(String format, Object... args) { 
    return new FormatterHALF_EVEN().format(format, args).toString(); 
} 
Смежные вопросы