Использование NSNumberFormatter для получения десятичного значения из строки международной валюты - PullRequest
20 голосов
/ 25 августа 2010

Кажется, что NSNumberFormatter не может разобрать строки валюты евро (и, возможно, других) в числовой тип.Может кто-то, пожалуйста, докажите, что я не прав.

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

NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *currencyNumber = [currencyFormatter numberFromString:currencyString];

Это прекрасно работает для сумм в валюте Великобритании и США.Он даже работает с разделителями $ и £ и тысячами без проблем.

Однако, когда я использую его с суммами в евро (с форматом региона, установленным в приложении настроек Франции или Германии), он возвращает пустую строку,Сбой всех следующих строк:

12,34 €
12,34
12.345,67 €
12.345,67

Стоит отметить, что эти строки точно совпадают с тем, что получается из метода stringFromNumber NSNumberFormatter при использовании соответствующего языкового стандарта.

Установка формата региона в Franceв настройках приложения, а затем установите для currencyNumber значение 12,34 в следующем коде, в результате чего currencyString будет иметь значение '12, 34 €':

NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *currencyString = [currencyFormatter stringFromNumber:currencyNumber];

Очевидно, было бы довольно легко обойти эту проблему специально дляевро, но я надеюсь продать это приложение в как можно большем количестве стран, и я думаю, что подобная ситуация неизбежно произойдет с другими регионами.

У кого-нибудь есть ответ?

TIA, Дункан

Ответы [ 7 ]

20 голосов
/ 10 октября 2010

Это сложный вопрос.Выполнение следующих операций работает без проблем:

double moneyAmount = 1256.34;
NSLocale *french = [[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"]; 
NSNumberFormatter *currencyStyle = [[NSNumberFormatter alloc] init];

[currencyStyle setLocale:french];
[currencyStyle setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *amount = [NSNumber numberWithDouble:moneyAmount];
NSString *amountString =  [currencyStyle stringFromNumber:amount];

NSNumber *pAmount = [currencyStyle numberFromString:amountString]; // == 1256.34

Однако выходные данные метода -currencyGroupingSeparator возвращают строку \u00a0, неразрывный пробел вместо ожидаемого ,.

Классы форматирования (а также классы регулярных выражений, среди прочих) в OS X / iOS используют библиотеку ICU , также используемую в других проектах.Я нашел по крайней мере два других сообщения об ошибках относительно этой конкретной проблемы.Похоже, что это ожидаемое поведение, хотя.(Я провел некоторое время, просматривая источник ICU, чтобы найти, где это определено, но это лабиринт.)

В настоящее время я рекомендую передать -setLenient:YES в средство форматирования валюты.Возможно, даже подайте отчет об ошибке с помощью радара Apple.

2 голосов
/ 04 декабря 2017

Рабочий код в Swift.

    let formatter = NumberFormatter()
    formatter.usesGroupingSeparator = true
    formatter.locale = Locale(identifier: "de_DE")  
    formatter.numberStyle = NumberFormatter.Style.currency
    formatter.string(from: NSNumber(floatLiteral: InputAsDoubleValue))!

Идентификаторы:

  • для Немецкий - "de_DE"
  • для US - "en_US"
  • для Франция - "fr_FR"

Отформатированное значение также будет возвращено с соответствующим символом валюты.

2 голосов
/ 28 октября 2011

Я убедился, что (по крайней мере, в iOS 4.3) использование флага [formatter setLenient: YES] работает для меня, используя евро.Если этот флаг не установлен, средство форматирования не возвращает правильные значения для евро.

2 голосов
/ 26 августа 2010

Вы пытались установить регион для Франции в настройках, а затем пытались получить числовую сумму для строки?Или вы можете вручную установить локальный форматировщик чисел с помощью setLocale:.NSNumberFormatter использует любой локаль, чтобы выяснить, какие числа являются строками.Если вам просто нужно, чтобы пользователь мог ввести строку локализованной валюты для своей области, измените систему на эту локаль, а затем протестируйте.Если вам нужно, чтобы пользователь мог использовать несколько форматов, добавьте какую-то систему выбора, чтобы вы знали, что они вводят.

1 голос
/ 05 мая 2011

У меня некрасивый ответ, используя вывод NSScanner

NSArray * testStrings = [NSArray arrayWithObjects:@"12,34 €", @"12,34" ,@"12.345,67 €" ,@"12.345,67", nil];

    NSCharacterSet * charset = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];

    for(NSString * s in testStrings)
    {
        s = [s stringByReplacingOccurrencesOfString:@"." withString:@""];
        s = [s stringByReplacingOccurrencesOfString:@"," withString:@"."];
        NSScanner * scanner = [NSScanner scannerWithString:s];
        [scanner setCharactersToBeSkipped:charset];
        float f;
        [scanner scanFloat:&f];
        NSLog(@"float output is %.2f",f);
    }

:2011-05-05 12: 56: 25.460 ScannerTest [10882: 903] с плавающей запятой равен 12,342011-05-05 12: 56: 25.473 ScannerTest [10882: 903] вывод с плавающей запятой равен 12,342011-05-05 12: 56: 25.474 ScannerTest [10882: 903] вывод с плавающей запятой 12345.672011-05-05 12: 56: 25.475 ScannerTest [10882: 903] вывод с плавающей запятой 12345.67

0 голосов
/ 26 октября 2014

Способ сделать это в Swift:

   var locale = NSLocale.currentLocale()
    var formatter = NSNumberFormatter()
    formatter.locale = NSLocale(localeIdentifier: "en_US")
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

    var moneyDouble = formatter.numberFromString(textField.text)?.doubleValue

Предполагается, что textField.text - это вводимый номер.

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

С настройками по умолчанию (lenient = NO), тогда он будет преобразовывать строки в числа только в том случае, если они отформатированы точно так же, как строки, которые он генерирует при форматировании чисел в строки.чтобы использовать не мягкие преобразования, вы должны знать, что во многих локалях (все?) это означает, что пробелы во входной строке должны быть неразрывными (\u00a0).То есть:

NSString *amount = @"10 000,00 €";

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterCurrencyStyle;

formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier: @"fr_FR"];

NSNumber *number = [currencyFormatter numberFromString: amount];

Это не приведет к ожидаемому результату, так как переменная number будет равна нулю.Чтобы получить желаемый результат, используйте неразрывные пробелы в обоих местах строки (как разделитель тысяч и разделитель символов валюты):

amount = @"10\u00a0000,00\u00a0€";

Тогда преобразование произойдет, как и ожидалось.

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

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

...