Как проанализировать Сумму валюты (США или EU) для плавания значения в Java

В дополнение к комментариям Майка Розенблюма об использовании массивов, я хотел бы добавить, что я использую сам подход (массивы VSTO +), и когда я измерял его, фактическая скорость чтения была в пределах миллисекунд. Просто не забудьте отключить обработку событий и обновление экрана перед чтением / записью, и не забудьте снова включить ее после завершения операции.

Используя C #, вы можете создавать массивы на основе 1 точно так же, как это делает сам Excel VBA. Это очень полезно, особенно потому, что даже в VSTO, когда вы извлекаете массив из объекта Excel.Range, массив основывается на 1, поэтому сохранение ориентированных на Excel массивов на основе 1 помогает избежать необходимости всегда проверять, является ли массив является единичным или основанным на нуле. (Если позиция столбца в массиве имеет для вас значение, то иметь дело с массивами на основе 0 и 1 может быть настоящей болью).

Вообще чтение Excel.Range в массив выглядело бы примерно так:

var myArray = (object[,])range.Value2;


В моем варианте записи массива Майка Розенблюма используется массив на основе 1, подобный этому:

int[] lowerBounds = new int[]{ 1, 1 };
int[] lengths = new int[] { rowCount, columnCount };  
var myArray = 
    (object[,])Array.CreateInstance(typeof(object), lengths, lowerBounds);

var dataRange = GetRangeFromMySources();

// this example is a bit too atomic; you probably want to disable 
// screen updates and events a bit higher up in the call stack...
dataRange.Application.ScreenUpdating = false;
dataRange.Application.EnableEvents = false;

dataRange = dataRange.get_Resize(rowCount, columnCount);
dataRange.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, myArray);

dataRange.Application.ScreenUpdating = true;
dataRange.Application.EnableEvents = true;
12
задан Sergio del Amo 8 June 2009 в 19:13
поделиться

2 ответа

Чтобы ответить на несколько иной вопрос: не используйте тип float для представления денежных значений. Он вас укусит . Вместо этого используйте тип с основанием 10, например BigDecimal , или целочисленный тип, например int или long (представляющий квант вашего значения - пенни, например, в валюте США).

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

Пример с этой страницы:

float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
// prints $12,571,782.00 (wrong)

BigDecimal a1 = new BigDecimal("8250325.12");
BigDecimal b1 = new BigDecimal("4321456.31");
BigDecimal c1 = a1.add(b1);
System.out.println(NumberFormat.getCurrencyInstance().format(c1));
// prints $12,571,781.43 (right)

Вы не хотите гадить ошибками, когда дело касается денег.

Что касается исходного вопроса, я уже давно не касался Java, но я знаю, что ' Я бы хотел держаться подальше от регулярных выражений, чтобы выполнять такую ​​работу. Я считаю, что это рекомендуется; это может вам помочь. Не проверено; предостережение разработчика.

try {
    String string = NumberFormat.getCurrencyInstance(Locale.GERMANY)
                                            .format(123.45);
    Number number = NumberFormat.getCurrencyInstance(locale)
                                            .parse("$123.45");
    // 123.45
    if (number instanceof Long) {
       // Long value
    } else {
       // too large for long - may want to handle as error
    }
} catch (ParseException e) {
// handle
}

Ищите регион с правилами, которые соответствуют тому, что вы ожидаете увидеть. Если вы не можете найти один, используйте несколько последовательно или создайте свой собственный пользовательский NumberFormat .

Я бы также подумал о том, чтобы заставить пользователей вводить значения в едином каноническом формате. 123.45 и 123.456 выглядят на мой вкус слишком похожими, и по вашим правилам могут привести к значениям, различающимся в 1000 раз. Вот как теряются миллионы .

канонический формат. 123.45 и 123.456 выглядят на мой вкус слишком похожими, и по вашим правилам могут привести к значениям, различающимся в 1000 раз. Вот как теряются миллионы .

канонический формат. 123.45 и 123.456 выглядят на мой вкус слишком похожими, и по вашим правилам могут привести к значениям, различающимся в 1000 раз. Вот как теряются миллионы .

35
ответ дан 2 December 2019 в 04:17
поделиться

Быстрый «грязный» взлом может быть следующим:

String input = input.replaceAll("\.,",""); // remove *any* , or .
long amount = Long.parseLong(input);

BigDecimal bd = BigDecimal.valueOf(amount).movePointLeft(2);

//then you could use:
bd.floatValue();
//but I would seriously recommended that you don't use floats for monetary amounts.

Обратите внимание, что это будет работать, только если ввод будет в форме ###. 00, то есть с ровно двумя десятичными знаками . Например, input == "10,022" сломает этот довольно наивный код.

Альтернативой является использование конструктора BigDecimal (String) , но вам нужно будет преобразовать эти евро номера стиля для использования '.' в качестве десятичного разделителя, помимо удаления разделителей тысяч для обоих.

-1
ответ дан 2 December 2019 в 04:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: