从Obj-C中的字符串中提取数字

时间:2013-03-20 05:17:09

标签: objective-c string nsstring normalization

我是Objective-C的新手,但在其他更高级的语言方面经验丰富。我想通过删除所有非数字字符来规范化字符串。换句话说,给定输入字符串“206-555-1212”,归一化结果应为“2065551212”。下面的代码片段有效,但鉴于我在其他语言中的经验看起来有点矫枉过正。有没有更好的方法呢?

编辑:输入字符串“(206)555-1212”,“206.555.1212”,“206 555 1212”等也应返回相同的标准化结果。

NSString * normalize(NSString * number)
{
    NSString *normalizedNumber = @"";
    NSString *tmpString = nil;

    NSRange searchRange;
    NSRange resultRange;
    searchRange.location = 0;
    searchRange.length = number.length;

    while (0 < searchRange.length)
    {
        resultRange = [number rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]
                                        options:NSLiteralSearch
                                          range:searchRange];
        tmpString = [number substringWithRange:resultRange];
        normalizedNumber = [normalizedNumber stringByAppendingString:tmpString];
        searchRange.location = resultRange.location + resultRange.length;
        searchRange.length = number.length - searchRange.location;
    }

    return normalizedNumber;
}

6 个答案:

答案 0 :(得分:12)

Resh32在their answer中将此代码建议用于类似的问题:

NSString * val = @"(555) 555-555 Office";
NSString * strippedNumber = [val stringByReplacingOccurrencesOfString:@"[^0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [val length])];
NSLog(@"%@", strippedNumber);

答案 1 :(得分:8)

所有这些答案都没有解决问题的“删除所有非数字字符”部分。这是一个简单的方法:

NSString *normalize(NSString *number) {
    NSMutableCharacterSet *nonNumberCharacterSet = [NSMutableCharacterSet decimalDigitCharacterSet];
    [nonNumberCharacterSet invert];

    return [[number componentsSeparatedByCharactersInSet:nonNumberCharacterSet] componentsJoinedByString:@""];
}

答案 2 :(得分:1)

我有一个小帮手方法:

+ (NSString *)strip:(NSString *)str keep:(NSString *)chars {
    NSCharacterSet *cs = [NSCharacterSet characterSetWithCharactersInString:chars];
    NSMutableString *res = [NSMutableString stringWithString:str];
    for (int i = [res length] - 1; i >= 0; i--) {
        if (![cs characterIsMember:[res characterAtIndex:i]]) {
            [res deleteCharactersInRange:NSMakeRange(i, 1)];
        }
    }

    return res;
}

可以像这样调用:

NSString *cleanString = [UtilityClass strip:originalString keep:@"0123456789+*#"];

答案 3 :(得分:1)

即使这个也可以使用:

NSString *s = @"234-1243-123";
NSString *ss=[[s componentsSeparatedByString:@"-"] componentsJoinedByString:@""];

答案 4 :(得分:0)

一个选项是创建一个NSFormatter子类来封装逻辑,或者使用一个开源的子类。 PhoneNumberFormatter看起来很有前途,并允许您删除格式,如下所示:

PhoneNumberFormatter *formatter = [[PhoneNumberFormatter alloc] init];
id objectValue;
NSError *error;
[formatter getObjectValue:&objectValue forString:@"1 (234) 567-8900" errorDescription:&error];
// objectValue = @"12345678900"

答案 5 :(得分:0)

这取决于您的具体目标。

如果您确定所有输入都是xxx-xxx-xxxx形式,这与removing all the whitespace form a string相同的基本问题(答案类似于已发布的答案),而不是删除你删除-字符的空格。摘要:使用-[NSString stringByReplacingOccurrencesOfString:withString:]-[NSString componentsSeparatedByCharactersInSet:]在这种情况下略微过度杀戮,但可能足以代替下面的NSScanner技术。

如果您尝试使用任意格式清理电话号码,那么您使用的方法是合理的,但如the answer to "Remove all but numbers from NSString"中所述,使用NSScanner会更加惯用。另请注意,如果您正在构建一个字符串(就像您的代码那样),那么使用NSMutableString和-appendString:而不是-[NSString stringByAppendingString:]会更有效率。

rmaddy's方法在这里也是一个很好的方法,但需要注意的是,它可能最适合作为NSString上的一个类别,其名称遵循Apple的惯例。

请注意,这些技术都不会 验证 一个电话号码,只能天真地从字符串中拉出10位数字。

最强大的解决方案是使用某种形式的专用电话号码检测器(la stuart的链接PhoneNumberFormatter)。

但是,如果您要做的是识别和提取电话号码而不必标准化数据,Apple会提供一个类NSDataDetector,可以为此配置。一个简单的例子如下所示:

NSError *error = nil;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:&error];

if(!detector) {
   NSLog(@"Error creating phone number detector: %@", [error localizedDescription]);
   return;
}

NSString *phoneNumberString = @"(555) 555-5555";

NSArray *matches = [detector matchesInString:phoneNumberString
                             options:0
                               range:NSMakeRange(0, [phoneNumberString length])];

if([matches count] < 1) {
   NSLog(@"No phone numbers found!");
   return;
}

NSTextCheckingResult *match = [matches lastObject];
if([match resultType] != NSTextCheckingTypePhoneNumber) {
    NSLog(@"Matched something, but not a phone number!");
    return;
}

NSString *phoneNumber = [match phoneNumber];
NSLog(@"Matched phone number: %@", phoneNumber);