Cocoa Dev
Cocoa Dev

Reputation: 9541

How can I format an NSTextField or UITextField?

I want to format any text that is placed into a NSTextField/UITextField to look like

###-###-####

Here are some possible inputs

1112223333
111.222.3333
(111)222-3333
(111) 2223333

Upvotes: 4

Views: 742

Answers (3)

Scott Marks
Scott Marks

Reputation: 652

Regular expressions are your friend:

NSString * reformat( NSString * number )
{
    NSRegularExpression * noDigits = 
        [ NSRegularExpression regularExpressionWithPattern: @"\\D" options: 0  error: NULL ] ;

    NSString * onlyDigits = [ noDigits stringByReplacingMatchesInString: number
                                                                options: 0
                                                                  range: NSMakeRange ( 0, number.length )
                                                           withTemplate: @"" ] ;

    NSRegularExpression * phoneNumberPattern =
        [ NSRegularExpression regularExpressionWithPattern: @"^(\\d\\d\\d)(\\d\\d\\d)(\\d\\d\\d\\d)$"
                                                   options: 0
                                                     error: NULL ] ;
    NSString * result = [ phoneNumberPattern stringByReplacingMatchesInString: onlyDigits 
                                                                      options: 0 
                                                                        range: NSMakeRange( 0, onlyDigits.length )
                                                                 withTemplate: @"$1-$2-$3" ] ;
    return result ;
}

You might want to check out some alternatives to the last pattern-matching replacement in case you are confronted with something other than 10 digits. Alternatively, put in a length check right afteronlyDigits is computed.

Upvotes: 1

Piyush Kashyap
Piyush Kashyap

Reputation: 1965

Try this method

-(void)NumberFormatter:(NSString *)originalString
{

    NSCharacterSet * set = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ"];

    if ([originalString rangeOfCharacterFromSet:set].location == NSNotFound) 
    {
        NSMutableString *strippedString = [NSMutableString 
                                           stringWithCapacity:originalString.length];

        NSScanner *scanner = [NSScanner scannerWithString:originalString];
        NSCharacterSet *numbers = [NSCharacterSet 
                                   characterSetWithCharactersInString:@"0123456789"];

        while ([scanner isAtEnd] == NO) {
            NSString *buffer;
            if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
                [strippedString appendString:buffer];

            } else {
                [scanner setScanLocation:([scanner scanLocation] + 1)];
            }
        }


        if ([strippedString length]<10) {
            NSLog(@"it is invalid string ,must contain atleast 10 numbers");
        }
        else
        {
            NSString *finalstring= [NSString stringWithFormat:@"%@-%@-%@",[strippedString substringWithRange:NSMakeRange(0, 3)],[strippedString substringWithRange:NSMakeRange(3, 3)],[strippedString substringFromIndex:6]];
            NSLog(@"This is the formatted number==%@",finalstring);
        }
    }
    else
        NSLog(@"string is invalid,It contains characters");
}

Upvotes: 0

colincameron
colincameron

Reputation: 2703

I've tested this code and it works for all of your examples:

- (NSString *)convertNumber:(NSString *)input {
    NSMutableString *result = [NSMutableString stringWithCapacity:15];
    NSScanner *scanner = [NSScanner scannerWithString:input];
    NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"1234567890"];
    NSString *temp;
    NSInteger location = 0;

    // Get first group
    [scanner scanUpToCharactersFromSet:numbers intoString:&temp];
    location = [scanner scanLocation];
    [scanner scanCharactersFromSet:numbers intoString:&temp];
    [result appendString:temp];

    if ([scanner scanLocation] < location + 4) {
        // Only scanned three numbers - get second group
        [scanner scanUpToCharactersFromSet:numbers intoString:&temp];
        location = [scanner scanLocation];
        [scanner scanCharactersFromSet:numbers intoString:&temp];
        [result appendString:temp];

        if ([scanner scanLocation] < location + 4) {
            // Only scanned three numbers - get last group
            [scanner scanUpToCharactersFromSet:numbers intoString:&temp];
            [scanner scanCharactersFromSet:numbers intoString:&temp];
            [result appendString:temp];
        }
    } else if ([scanner scanLocation] < location + 7) {
        // Scanned six numbers - get last group
        [scanner scanUpToCharactersFromSet:numbers intoString:&temp];
        [scanner scanCharactersFromSet:numbers intoString:&temp];
        [result appendString:temp];
    }

    // Add dashes
    if ([result length] > 6) {
        [result insertString:@"-" atIndex:3];
        [result insertString:@"-" atIndex:7];
    }

    return result;
}

Any quantity of non-numeric characters (or none) between the groups of 3, 3 and 4 will be ignored.

Warning: it may leak all over the place, and could crash if given unexpected input.

Upvotes: 3

Related Questions