如何检查字符串是否包含考虑本地化数字格式的有效数字。
这个问题不是转换数字的主要问题。我可以用NSNumberFormatter做到这一点。如果我不能,那么我甚至不需要这样做,并可以将字符串保留为字符串。但我需要检查它是否包含有效的数字。
顺便说一下,我们正处于textField:shouldChangeCharactersInRange:...委托方法的中间。在这里,我想通过返回NO来防止键入非法字符。这是我的代码:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Only test for numbers if it is a certain text field.
if (textField == self.numValueTextField) {
NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string];
// The user deleting all input is perfectly acceptable.
if ([resultingString length] == 0) {
return true;
}
double holder;
NSScanner *scan = [NSScanner scannerWithString: resultingString];
BOOL isNumeric = [scan scanDouble: &holder] && [scan isAtEnd];
if (isNumeric) {
[self.detailItem setValue:number forKey:kValueDouble];
}
return isNumeric;
}
return YES; // default for any other text field - if any.
}
这样可行,但它暗示英文符号。意思是浮点必须是pont。但它可能是一个逗号或世界某些地方的任何东西。
我知道如何检查某些字符。所以我可以检查0-9,逗号和点。但这样做有“适当的”方式吗?
如果它很重要:我在iOS环境中。
答案 0 :(得分:7)
默认情况下,数字格式化程序将使用当前语言环境的信息,因此它应该能够为您执行此检查。只是尝试格式化字符串。如果结果为nil
,那么它无效。
static NSNumberFormatter * formatter = [NSNumberFormatter new];
//... build string
NSNumber * num = [formatter numberFromString:resultingString];
BOOL isNumeric = (num != nil);
例如:
NSNumberFormatter * formatter = [NSNumberFormatter new];
// US uses period as decimal separator
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
NSLog(@"%@", [formatter numberFromString:@"3.1415"]); // Valid NSNumber
NSLog(@"%@", [formatter numberFromString:@"3.14.15"]); // nil
NSLog(@"%@", [formatter numberFromString:@"31415"]); // Valid
NSLog(@"%@", [formatter numberFromString:@"3,1415"]); // nil
// Italy uses a comma as decimal separator
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"it"]];
NSLog(@"%@", [formatter numberFromString:@"3.1415"]); // nil
NSLog(@"%@", [formatter numberFromString:@"3.14.15"]); // nil
NSLog(@"%@", [formatter numberFromString:@"31415"]); // Valid
NSLog(@"%@", [formatter numberFromString:@"3,1415"]); // Valid
或者您可能更喜欢使用getObjectValue:forString:range:error:
,它只会返回YES
或NO
来表示解析成功,如果您对进一步感兴趣,还会给您一个错误对象的信息。
答案 1 :(得分:2)
我就是这样做的。您想要的关键信息是[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]
,它将告诉您当前的小数分隔符。然后,您将查找不在法律集合中的任何字符。
- (BOOL)isLegalDigitString:(NSString *)string
forTextField:(UITextField *)textField
hasDecimalPoint:(BOOL)hasDecimalPoint
{
// It's always legal to delete
if ([string length] == 0)
{
return YES;
}
// Only legal characters
NSString *decimalSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
NSString *legalCharacters = [@"1234567890" stringByAppendingString:
(hasDecimalPoint ? decimalSeparator
: @"")];
NSCharacterSet *forbiddenCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:legalCharacters] invertedSet];
if ([string rangeOfCharacterFromSet:forbiddenCharacterSet].location != NSNotFound)
{
return NO;
}
// Only one decimal point
if (hasDecimalPoint &&
[string rangeOfString:decimalSeparator].location != NSNotFound &&
[[textField text] rangeOfString:decimalSeparator].location != NSNotFound)
{
return NO;
}
return YES;
}
作为我如何使用它的一个例子:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == [self integerTextField])
{
return [self isLegalDigitString:string forTextField:textField hasDecimalPoint:NO];
}
else if (textField == [self floatTextField])
{
return [self isLegalDigitString:string forTextField:textField hasDecimalPoint:YES];
}
return YES;
}
这个做得不好的一件事是管理有限的精度(例如,一个只能有十分之一的字段)。需要对此进行一些重新设计。
答案 2 :(得分:0)
您可以使用NSLocale获取本地化的分组分隔符,然后将其从字符串中删除,因为NSScanner不处理分组。
NSString *sep = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
NSString *string2 = [string1 stringByReplacingOccurrencesOfString:sep withString:@""];
初始化一个考虑了本地化小数分隔符的NSScanner。
NSScanner *scan = [NSScanner localizedScannerWithString:string2];
然后按原样继续使用NSScanner代码。使用NSScanner比手动编码方法更强大,因为它处理所有符合IEEE标准的数字,包括+/-和科学记数法。它也更短。
答案 3 :(得分:0)
坦率地说,任何对有效数字的测试都应该适用于部分数字,这是非常棘手的。
请勿尝试重新实施NSNumberFormatter
中已实施的检查。不同的语言使用不同的小数分隔符,但也使用不同的数字(编辑:不幸的是,NSNumberFormatter
也无法验证非阿拉伯数字。)
有许多特殊情况不是有效数字,但可以成为有效数字,例如空字符串,减号,小数点分隔符,减号与小数点分隔符组合。如果你允许使用科学记数法,那将会变得更加复杂。
最简单的解决方案是仅检查最终号码。用户确认后检查输入(点击输入,点击输入视图外部。)
但是,请注意NSNumberFromatter
实际上可以验证部分字符串。有关详细信息,请参阅其超类NSFormatter
。