我一直在使用以下方法将NSString解析为NSNumber:
// (a category method on NSString)
-(NSNumber*) tryParseAsNumber {
NSNumberFormatter* formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
return [formatter numberFromString:self];
}
我进行了测试,验证这是正确的工作:
test(@"".tryParseAsNumber == nil);
...
test([(@NSUIntegerMax).description.tryParseAsNumber isEqual:@NSUIntegerMax]);
...
当我切换到在iPhone 6上进行测试时,最大值测试开始失败,可能是因为NSUInteger现在是64位而不是32位。格式化程序返回的值现在是双1.844674407370955e+19
,而不是uint64_t 18446744073709551615
。
有没有一个内置方法可以完全成功地处理所有的int64和无符号int64,或者我必须自己实现一个?
+ [NSNumber numberWithLongLong:]
+ [NSNumber numberWithUnsignedLongLong:]
你试过这些吗?
编辑
我完全不确定你最终会对NSNumber
的实例做什么,但考虑到NSDecimalNumber
似乎正是你想要做的:
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:@"18446744073709551615"];
NSLog(@"%@", decNum);
产生:
2014-09-21 15:11:25.472 Test[1138:812724] 18446744073709551615
还有一点需要考虑:NSDecimalNumber
"是"NSNumber
,因为它是后者的子类。因此,无论你能用NSNumber
做什么,你都可以用NSDecimalNumber
做。
NSDecimalNumber decimalNumberWithString:
能够完全精确地进行解析,但它允许一些错误的输入(例如,"88ffhih"被解析为88)。另一方面,NSNumberFormatter numberFromString:
总是检测到错误的输入,但会失去精度。他们有相反的弱点。
所以。。。两者兼而有之。例如,这里有一个方法应该解析可表示的NSUIntegers,但不解析其他内容:
+(NSNumber*) parseAsNSUIntegerElseNil:(NSString*)decimalText {
// NSNumberFormatter.numberFromString is good at noticing bad inputs, but loses precision for large values
// NSDecimalNumber.decimalNumberWithString has perfect precision, but lets bad inputs through sometimes (e.g. "88ffhih" -> 88)
// We use both to get both accuracy and detection of bad inputs
NSNumberFormatter* formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
if ([formatter numberFromString:decimalText] == nil) {
return nil;
}
NSNumber* value = [NSDecimalNumber decimalNumberWithString:decimalText];
// Discard values not representable by NSUInteger
if (![value isEqual:@(value.unsignedIntegerValue)]) {
return nil;
}
return value;
}