Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 从特定于区域设置的字符串中获取NSDecimalNumber?_Iphone_Objective C_Cocoa_Cocoa Touch_Internationalization - Fatal编程技术网

Iphone 从特定于区域设置的字符串中获取NSDecimalNumber?

Iphone 从特定于区域设置的字符串中获取NSDecimalNumber?,iphone,objective-c,cocoa,cocoa-touch,internationalization,Iphone,Objective C,Cocoa,Cocoa Touch,Internationalization,我有一些特定于语言环境的字符串(例如,0.01或0,01)。我想把这个字符串转换成小数。从中,这是通过使用NSNumberFormatter a la来实现的: NSString *s = @"0.07"; NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; [formatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; [formatter setGe

我有一些特定于语言环境的字符串(例如,0.01或0,01)。我想把这个字符串转换成小数。从中,这是通过使用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模式(除了文档中推荐的模式外,它也是iPhone上唯一可用的模式),但向格式化程序指示我要生成十进制数。请注意,我简化了我的示例(实际上我处理的是货币字符串)。然而,我显然做了一些错误的事情,因为它返回了一个说明浮点数不精确的值

将特定于语言环境的数字字符串转换为NSDecimalNumber的正确方法是什么

编辑:注意我的示例是为了简单。我要问的问题还应该与何时需要获取特定于语言环境的货币字符串并将其转换为NSDecimalNumber有关。此外,还可以将其扩展为特定于语言环境的百分比字符串,并将其转换为NSDecimalNumber。

这似乎有效:

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
另外,在这个问题上提交一个bug。这绝对不是你在那里看到的正确行为


编辑:在苹果解决这个问题之前(然后每个潜在用户都会更新到固定的OSX版本),您可能需要使用NSScanner滚动您自己的解析器,或者对输入的数字接受“仅”双精度。除非你计划在这个应用程序中加入五角大楼的预算,否则我建议你使用后者。事实上,双倍数字精确到小数点后14位,因此,如果少于一万亿美元,它们就会少掉一分钱。我不得不为一个项目编写自己的基于NSDateFormatter的日期解析例程,我花了一个月的时间处理所有有趣的edge案例(比如只有瑞典的长日期中包含了星期几)。

根据Boaz Stuler的回答,我就这个问题向苹果公司记录了一个bug。在这个问题解决之前,以下是我认为最好的解决办法。这些解决方法仅仅依赖于将十进制数四舍五入到适当的精度,这是一种可以补充现有代码的简单方法(而不是从格式化程序切换到扫描程序)

一般数字

基本上,我只是根据对我的情况有意义的规则对数字进行四舍五入。因此,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
另见

处理货币的最佳方法是对货币的最小单位使用整数值,即美元/欧元等于美分等。这样可以避免代码中与浮点相关的精度错误

考虑到这一点,解析包含货币值的字符串的最佳方法是手动执行(使用可配置的小数点字符)。在小数点处拆分字符串,并将第一部分和第二部分都解析为整数值。然后使用这些值构建组合值。

几年后:


+(NSDecimalNumber*)带字符串的十进制数:(NSString*)numericString
NSDecimalNumber
中记录错误#6400434。谢谢你的回复。正如我提到的,我的例子被简化了(我实际上是在处理货币问题)。因此,我不确定这个答案是否适用于这个场景。Boaz Stuler-请参阅我的答案,其中说明了一个代码片段,它可以非常简单地处理这个问题,而不使用自定义解析器/NSScanner…并且在五角大楼的预算范围内。;)谢谢你的回答,森。你的评论是处理货币问题的一个很好的经验法则(我已经在这么做了)。但是,与您所描述的手动解析输入货币字符串不同,请参阅我的答案中的代码示例,这些示例更优雅地处理了此问题。具体而言,我的代码示例演示了跨任何语言环境处理货币字符串输入。这比手动解析字符串和解释分组、十进制分隔符、货币符号等各种特定于语言环境的规则要容易得多。只需注意,您应该将格式化程序的编号转换为指向NSDecimalNumber的指针。即NSDecimalNumber*decimalNumber=(NSDecimalNumber*)[formatter numberFromString:s];注意某些地区的小数分隔符不同。例如,在法语中,我们用逗号“,”来分隔小数。在那种情况下,这行不能正确转换<代码>[NSDecimalNumber decimalNumberWithString:string语言环境:[NSLocale currentLocale]]工作正常,但是:)这在2020年似乎不起作用:NSDecimalNumber(字符串:“9277.235”)-->9277.235000000001