Как отформатировать число в зависимости от локали, сохранив все десятичные точки? - PullRequest
1 голос
/ 13 мая 2019

Я пытаюсь использовать DecimalFormat для преобразования десятичного разделителя в двойное значение, сохраняя при этом все десятичные дроби исходного числа. DecimalFormatter принимает шаблон в формате: "0. ##", например. Поскольку мне приходится использовать числа с разными десятичными знаками, это не сработает, поскольку в шаблоне всегда нужно указывать количество десятичных знаков.

Я ищу способ обойти это.

Я пробовал String.format. DecimaFormatter и NumberFormatter

В идеале я хотел бы что-то вроде:

  private static final ThreadLocal< DecimalFormat > formatter = new ThreadLocal< DecimalFormat >() 
  {
    @Override
    protected DecimalFormat initialValue() 
    {
    // n should be any number of decimals without having to specify them.
      return new DecimalFormat("0.0#n");     
    }
  };

Некоторые примеры:

DecimalFormat df = new DecimalFormat("0.0##");
System.out.println(df.format(2.456))
System.out.println(df.format(2.1));

Результат:

2,456 -> Good
2,100 -> Not good

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

2,456 -> Good
2,1 -> Good
3,3453456345234 -> Good

Ответы [ 3 ]

2 голосов
/ 13 мая 2019

Числа в Java (и просто числа, как правило) не имеют заданного количества десятичных знаков.1.1, 1.10 и 1.100 являются точно одним и тем же числом.

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

String str = num.toString();
int decimal = str.indexOf('.');
int places = decimal <= 0 ? 0 : str.length - decimal;

... а затем укажите столько мест при использовании форматера.

0 голосов
/ 13 мая 2019

DecimalFormat имеет 16 методов установки для управления выходом. Строка шаблона, которую вы указываете в конструкторе, является просто удобным способом установки большинства этих значений.

Для управления локали вывода можно указать DecimalFormatSymbols либо в конструкторе, либо в методе установки .

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

Пример * * тысяча двадцать-один

private static void test(Locale locale) {
    DecimalFormat fmt = new DecimalFormat("0.0", DecimalFormatSymbols.getInstance(locale));
    //fmt.setMaximumIntegerDigits(Integer.MAX_VALUE); // already set by pattern
    //fmt.setMinimumIntegerDigits(1);                 // already set by pattern
    //fmt.setMinimumFractionDigits(1);                // already set by pattern
    fmt.setMaximumFractionDigits(Integer.MAX_VALUE);
    //fmt.setGroupingUsed(false);                     // already set by pattern

    System.out.println(locale.toLanguageTag() + " (" + locale.getDisplayLanguage(Locale.US) +
                                               " - " + locale.getDisplayCountry(Locale.US) + ")");
    System.out.println("  " + fmt.format(123456789));
    System.out.println("  " + fmt.format(2.456));
    System.out.println("  " + fmt.format(2.1));
    System.out.println("  " + fmt.format(3.3453456345234));
}

public static void main(String[] args) {
    test(Locale.US);
    test(Locale.GERMANY);
    test(Locale.forLanguageTag("ar-EG"));
}

Выход (OpenJDK 11.0.1)

en-US (English - United States)
  123456789.0
  2.456
  2.1
  3.3453456345234
de-DE (German - Germany)
  123456789,0
  2,456
  2,1
  3,3453456345234
ar-EG (Arabic - Egypt)
  ١٢٣٤٥٦٧٨٩٫٠
  ٢٫٤٥٦
  ٢٫١
  ٣٫٣٤٥٣٤٥٦٣٤٥٢٣٤
0 голосов
/ 13 мая 2019

Итак, у вас есть

double[] floats = { 3.20, 4.500, 6.34, 1.0000 };
BigDecimal[] fixeds = {
    new BigDecimal("3.20"),
    new BigDecimal("4.500"),
    new BigDecimal("6.34"),
    new BigDecimal("1.0000")
};

и вы хотите отформатировать их как таковые, но локализовано.

Хорошая новость заключается в том, что числа с фиксированной точкой с BigDecimal поддерживают точность (с помощью строкового конструктора)).Плохая новость заключается в том, что число с плавающей запятой всегда приблизительно, суммой (отрицательных) степеней 2. Таким образом, 3,20 может фактически быть 3,19999987 или 3.20000043.

У них нет фиксированных десятичных знаков.Даже без ошибки аппроксимации 3.2 == 3.20 == 3.200.

Так что конвертируйте в BigDecimal (довольно некрасиво) и избавьтесь от ошибок аппроксимации: 1000 * 3.2! = 3200.0.

BigDecimal value = new BigDecimal("5.1000");
NumberFormat df = NumberFormat.getInstance(Locale.KOREA);
df.setMinimumFractionDigits(value.getScale()); // 4
String s = df.format(value);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...