Получение NSDecimalNumber из определенной в локали строки?

У меня есть строка s, которая зависит от локали (например, 0,01 или 0,01). Я хочу преобразовать эту строку в NSDecimalNumber. Из примеров, которые я видел до сих пор в средах , это достигается с помощью NSNumberFormatter a la:

NSString *s = @"0.07"; NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; [formatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; [formatter setGeneratesDecimalNumbers:YES]; NSDecimalNumber *decimalNumber = [formatter numberFromString:s]; NSLog([decimalNumber stringValue]); // prints 0.07000000000000001 

Я использую режим 10.4 (в дополнение к тому, чтобы быть рекомендованным в документации, это также единственный режим, ansible на iPhone), но указывающий на форматтер, который я хочу создать десятичные числа. Обратите внимание, что я упростил свой пример (я действительно имею дело с валютными строками). Однако я, очевидно, что-то не так, чтобы вернуть значение, которое иллюстрирует неточность чисел с плавающей запятой.

Каков правильный метод преобразования определенной строки строки в NSDecimalNumber?

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

Годы спустя:

+(NSDecimalNumber *)decimalNumberWithString:(NSString *)numericString в NSDecimalNumber .

Основываясь на ответе Boaz Stuller, я зарегистрировал ошибку для Apple по этой проблеме. Пока это не будет разрешено, вот обходные решения, которые я решил использовать как лучший подход. Эти обходные пути просто полагаются на округление десятичного числа до соответствующей точности, что является простым подходом, который может дополнять ваш существующий код (а не переключиться с форматирования на сканеры).

Общие номера

По сути, я просто округлю число, основанное на правилах, которые имеют смысл для моей ситуации. Таким образом, YMMV зависит от точности, которую вы поддерживаете.

 NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; [formatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; [formatter setGeneratesDecimalNumbers:TRUE]; NSString *s = @"0.07"; // Create your desired rounding behavior that is appropriate for your situation NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE]; NSDecimalNumber *decimalNumber = [formatter numberFromString:s]; NSDecimalNumber *roundedDecimalNumber = [decimalNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior]; NSLog([decimalNumber stringValue]); // prints 0.07000000000000001 NSLog([roundedDecimalNumber stringValue]); // prints 0.07 

валюты

Обработка валют (это реальная проблема, которую я пытаюсь решить) – это всего лишь небольшая вариация при обработке общих чисел. Ключ состоит в том, что масштаб поведения округления определяется максимальными дробными цифрами, используемыми валютой локали.

 NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init]; [currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; [currencyFormatter setGeneratesDecimalNumbers:TRUE]; [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; // Here is the key: use the maximum fractional digits of the currency as the scale int currencyScale = [currencyFormatter maximumFractionDigits]; NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:currencyScale raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE]; // image s is some locale specific currency string (eg, $0.07 or €0.07) NSDecimalNumber *decimalNumber = (NSDecimalNumber*)[currencyFormatter numberFromString:s]; NSDecimalNumber *roundedDecimalNumber = [decimalNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior]; NSLog([decimalNumber stringValue]); // prints 0.07000000000000001 NSLog([roundedDecimalNumber stringValue]); // prints 0.07 

Это похоже на работу:

 NSString *s = @"0.07"; NSScanner* scanner = [NSScanner localizedScannerWithString:s]; NSDecimal decimal; [scanner scanDecimal:&decimal]; NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithDecimal:decimal]; NSLog([decimalNumber stringValue]); // prints 0.07 

Также сообщите об ошибке. Это определенно не правильное поведение, которое вы видите там.

Изменить: пока Apple не исправляет это (а затем каждый потенциальный пользователь обновляется до фиксированной версии OSX), вам, вероятно, придется сворачивать свой собственный парсер с помощью NSScanner или принимать двойную точность «только» для введенных номеров. Если вы планируете иметь бюджет Пентагона в этом приложении, я бы предложил его. Реально, удваивается с точностью до 14 знаков после запятой, поэтому на сумму менее триллиона долларов они будут меньше, чем копейки. Мне пришлось написать свои собственные процедуры синтаксического анализа на основе NSDateFormatter для проекта, и я потратил буквально месяц на обработку всех смешных крайних случаев (например, как только Швеция имеет день недели, включенный в ее длинную дату).

См. Также Лучший способ хранения значений валюты в C ++

Лучшим способом обработки валюты является использование целочисленного значения для наименьшей единицы валюты, т. Е. Центов за доллары / евро и т. Д. Вы избежите ошибок точности, связанных с плавающей точкой, в вашем коде.

Имея это в виду, лучший способ проанализировать строки, содержащие значение валюты, – это сделать это вручную (с настраиваемым символом десятичной точки). Разделите строку в десятичной точке и проанализируйте как первую, так и вторую часть как целочисленные значения. Затем используйте построение своего комбинированного значения.

  • Добавление файлов в отдельные объекты в Xcode 4
  • Можно ли смешивать Swift с C ++? Как и файлы Objective - C .mm
  • Могут ли новые литералы Clang Objective-C перенаправляться на пользовательские classы?
  • Загрузка изображения через POST в Objective C
  • Извлечение текста pdf в Objective C
  • Как узнать, кто вызвал метод?
  • Напишите UIImage вместе с метаданными (EXIF, GPS, TIFF) в библиотеке фотографий iPhone
  • Как я могу получить UIBarButtonItem с изображением и текстом?
  • В чем разница между строковой константой и строковым литералом?
  • Добавление объекта C ++ в Objective-C Class
  • Почему обесцвечиваются зонтичные frameworks?
  • Давайте будем гением компьютера.