extract digits from string in Obj-C [duplicate]

2020-07-22 04:15发布

问题:

I'm new to Objective-C, but experienced in other higher languages. I want to normalize a string by removing all non-numeric characters. In other words given the input string "206-555-1212" the normalized result should be "2065551212". The code snippet below works, but given my experience in other languages that seems like overkill. Is there a better way to do it?

EDIT: The input strings "(206) 555-1212", "206.555.1212", "206 555 1212", etc. should also return the same normalized result.

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;
}

回答1:

All of these answers don't address the "removing all non-numeric characters" part of the question. Here's a simple way to do it:

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

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


回答2:

Resh32 suggests this code in their answer to a similar question:

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


回答3:

I have a little helper method for this:

+ (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;
}

It can be called like this:

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


回答4:

Even this one will work:

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


回答5:

One option would be creating an NSFormatter subclass to encapsulate the logic, or use an open source one. PhoneNumberFormatter looks promising, and lets you remove formatting as follows:

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


回答6:

This depends on your specific goal.

If you are really certain that all of your input will be of the form xxx-xxx-xxxx, this is the same basic question as removing all the whitespace form a string (with answers similar to those already posted), only instead of removing whitespace you are removing the - character. Summary: use -[NSString stringByReplacingOccurrencesOfString:withString:] (-[NSString componentsSeparatedByCharactersInSet:] is slight over-kill in this case, but may be sufficient to use in place of the NSScanner technique below).

If you are trying to sanitize phone numbers with an arbitrary format, the approach you're using is reasonable, however it would be slightly more idiomatic to use an NSScanner as described in the answer to "Remove all but numbers from NSString". Also note that if you're building up a string (as your code is), it is far more efficient to use an NSMutableString and -appendString: rather than -[NSString stringByAppendingString:].

rmaddy's approach is also a good one here, with the caveat that it would probably make the most sense as a category on NSString with a name that follows Apple's conventions.

Note that none of these techniques will validate a phone number, only naïvely pull the base-10 digits from a string.

The most robust solution would be to use some form of dedicated phone number detector (a la Stuart's linked PhoneNumberFormatter).

However, if what you want to do is identify and extract phone numbers without necessarily normalizing your data, Apple provides a class, NSDataDetector, that can be configured for this purpose. A simple example would look like this:

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);