Замените группирующий разделитель DecimalFormat в отформатированном значении

Я использовал DecimalFormat df = new DecimalFormat("#,###.00"); для форматирования BigDecimal.

Теперь я хочу использовать это отформатированное значение (скажем, «1 250,00») для создания new BigDecimal. Я пробовал это:

BigDecimal result = new BigDecimal(model.getValue().replace(",",".").replace(" ",""));

Но это space между 1 и 2 в 1 250.00 не заменяется. Как я могу это исправить?

Пример:

DecimalFormat df = new DecimalFormat("#,###.00");
BigDecimal example = new BigDecimal("1250");
String str = df.format(example);
System.out.println(str.replace(",",".").replace(" ",""));

person rakamakafo    schedule 03.09.2015    source источник
comment
У вас может быть другой вид пробелов. Вместо этого попробуйте использовать replaceAll("\\s+", "").   -  person Mena    schedule 03.09.2015
comment
Попробовал ваш код, для String s ="1 250,00" работает нормально. Так что проблема не в методе замены   -  person SacJn    schedule 03.09.2015
comment
@Tunaki, я привел пример. Попытайся. Моя локализация - Москва/Россия, если это поможет. выход - 1 250.00   -  person rakamakafo    schedule 03.09.2015


Ответы (4)


DecimalFormat Javadoc указывает, что символ , является групповой разделитель. По умолчанию для вашей локали этим разделителем является не пробел, а неразрывный пробел. Это можно показать с помощью следующего кода:

DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.forLanguageTag("ru-RU"));
System.out.println((int) symbols.getGroupingSeparator());

Вы увидите, что напечатанное int равно 160, что соответствует "Неразрывный пробел" в ISO-8859-1.

Чтобы удалить этот символ, мы можем использовать его представление Unicode и заменить его:

DecimalFormat df = new DecimalFormat("#,###.00");
String str = df.format(new BigDecimal("1250"));
System.out.println(str.replace(",", ".").replace("\u00A0", ""));

Для более общего решения, не зависящего от текущей локали, мы могли бы получить разделитель группировки и использовать его напрямую:

DecimalFormat df = new DecimalFormat("#,###.00");
String groupingSeparator = String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator());
String str = df.format(new BigDecimal("1250"));
System.out.println(str.replace(",", ".").replace(groupingSeparator, ""));
person Tunaki    schedule 03.09.2015

Вы можете установить символ разделитель группировки (например, разделитель тысяч) в своем шаблоне, используя DecimalFormatSymbols. Похоже, что в вашей локали это неразрывное пространство, поэтому попробуйте установить его на обычное пространство, например

DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.getDefault());
symbols.setGroupingSeparator(' ');//simple space

DecimalFormat df = new DecimalFormat("#,###.00", symbols);

BigDecimal example = new BigDecimal("1250");
String str = df.format(example);

Теперь ваш форматтер будет использовать простое пространство, поэтому вы сможете заменить его своим кодом.

System.out.println(str.replace(",", ".").replaceAll(" ", ""));

Выход: 1250.00.

person Pshemo    schedule 03.09.2015

Вы можете использовать метод parse из вашего объекта DecimalFormat.

df.setParseBigDecimal(true);    
BigDecimal bigDecimal = (BigDecimal) df.parse(model.getValue());

Взгляните на выбранный ответ в этом вопросе SO.

person Milan Milanov    schedule 03.09.2015
comment
df.parse(str) может возвращать тип, отличный от BigInteger, например, он может возвращать Long. Вы можете изменить свое решение на что-то вроде new BigDecimal(df.parse(model.getValue()).toString()); - person Pshemo; 03.09.2015
comment
Если число отформатировано и проанализировано с помощью одного и того же объекта DecimalFormat, оно должно работать. - person Milan Milanov; 03.09.2015
comment
Не обязательно. df.parse(df.format(BigDecimal.ONE)).getClass() возвращает мне class java.lang.Long. - person Pshemo; 03.09.2015
comment
На самом деле теперь я вижу, что ваше исходное решение было лучше, потому что оно позволяет избежать потери точности в случае двойных значений. Все, что вам нужно добавить, это df.setParseBigDecimal(true);, чтобы гарантировать, что все вызовы df.parse будут возвращать BigDecimal. - person Pshemo; 03.09.2015
comment
Это также упоминается в вопросе SO, на который я ссылался, но спасибо за явное указание на это (даже мне). - person Milan Milanov; 03.09.2015

В вашем формате

new DecimalFormat("#,###.00"); 

символ , предназначен для группового разделителя. После удаления символа , из вашего формата вы получите вывод 1250.00 (без группового разделителя в вашем случае пробел).

DecimalFormat df = new DecimalFormat("####.00");
BigDecimal example = new BigDecimal("1250");
String str = df.format(example);
System.out.println(str.replace(",",".").replace(" ",""));

Выход: 1250.00

Существует альтернативное (второе) решение, и оно работает без изменения вашего формата "#,###.00". Используйте .setGroupingSize(0) из десятичного формата:

DecimalFormat df = new DecimalFormat("#,###.00");
df.setGroupingSize(0);
BigDecimal example = new BigDecimal("1250");
String str = df.format(example);
System.out.println(str);

Выход: 1250.00

person Developer Marius Žilėnas    schedule 03.09.2015
comment
Но я должен использовать ',' в декоративных целях - person rakamakafo; 03.09.2015
comment
с .setGroupingSize(0) вы можете сохранить в своем формате. - person Developer Marius Žilėnas; 03.09.2015
comment
Метод какого класса?) - person rakamakafo; 03.09.2015
comment
Это метод DecimalFormat (см. docs.oracle.com/javase/7/docs/api/java/text/ ). Вы объявляете DecimalFormat df = new DecimalFormat(#,###.00); а затем выполните df.setGroupingSize(0);, чтобы установить параметр десятичного формата. - person Developer Marius Žilėnas; 03.09.2015
comment
df.setGroupingSize (0); не работает, т.е. нет разделителя тысяч - person rakamakafo; 03.09.2015