Last Updated: February 25, 2016
·
4.702K
· pxpgraphics

Quick Formatting of Credit Card Numbers

Ever wonder how you could format a credit card number in your app? Maybe you've tried a few different ways, for example: stringByReplacingOccurrencesOfString:withString:options:range

Well, let's save you some time with Regular Expressions :)

Please, step into my office—

 NSString *formattedCCNumber;
if ([self.creditCardNumber length] == 16) {
        formattedCCNumber = [self.creditCardNumber stringByReplacingOccurrencesOfString:@"(\\d{4})(\\d{4})(\\d{4})(\\d+)" withString:@"$1-$2-$3-$4" options:NSRegularExpressionSearch range:NSMakeRange(0, [self.creditCardNumber length])];
} else if ([self.creditCardNumber length] == 15) {
        formattedCCNumber = [self.creditCardNumber stringByReplacingOccurrencesOfString:@"(\\d{4})(\\d{6})(\\d+)" withString:@"$1-$2-$3" options:NSRegularExpressionSearch range:NSMakeRange(0, [self.creditCardNumber length])];
}

self.ccNumberTextField.text = formattedCCNumber;

And below is the method we replaced in stringByReplacingOccurrencesOfString:withString:options:range

NSString *text = [textField text];
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789\b"];
            string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""];
            if ([string rangeOfCharacterFromSet:[characterSet invertedSet]].location != NSNotFound) {
                return NO;
            }

            text = [text stringByReplacingCharactersInRange:range withString:string];
            text = [text stringByReplacingOccurrencesOfString:@"-" withString:@""];

            // Change credit card display for AMEX.
            if ([text length] > 1 && [text characterAtIndex:0] == '3' && ([text characterAtIndex:1] == '4' || [text characterAtIndex:1] == '7')) {
                NSString *newString = @"";
                while (text.length > 0) {
                    // First set of numbers.
                    NSString *subString1 = [text substringToIndex:MIN(text.length, 4)];
                    newString = [newString stringByAppendingString:subString1];
                    if (subString1.length == 4) {
                        newString = [newString stringByAppendingString:@"-"];
                    }
                    if (subString1.length < 5) {
                        text = [text substringFromIndex:MIN(text.length, 4)];
                    }
                    // Second set of numbers.
                    NSString *subString2 = [text substringToIndex:MIN(text.length, 6)];
                    newString = [newString stringByAppendingString:subString2];
                    if (subString2.length == 6) {
                        newString = [newString stringByAppendingString:@"-"];
                    }
                    if (subString2.length < 7) {
                        text = [text substringFromIndex:MIN(text.length, 6)];
                    }
                    // Third set of numbers.
                    NSString *subString3 = [text substringToIndex:MIN(text.length, 5)];
                    newString = [newString stringByAppendingString:subString3];
                    if (subString3.length < 16) {
                        text = [text substringFromIndex:MIN(text.length, 15)];
                    }
                }
                newString = [newString stringByTrimmingCharactersInSet:[characterSet invertedSet]];
                if (newString.length > 17) {
                    return NO;
                }
                [textField setText:newString];
                return NO;
            } else {
                // Display credit card number in sections of 4 for all other issuers.
                NSString *newString = @"";
                while (text.length > 0) {
                    NSString *subString = [text substringToIndex:MIN(text.length, 4)];
                    newString = [newString stringByAppendingString:subString];
                    if (subString.length == 4) {
                        newString = [newString stringByAppendingString:@"-"];
                    }
                    text = [text substringFromIndex:MIN(text.length, 4)];
                }
                newString = [newString stringByTrimmingCharactersInSet:[characterSet invertedSet]];
                if (newString.length > 19) {
                    return NO;
                }
                [textField setText:newString];
                return NO;
            }

The first example is much more concise and legible. But it's up to you to choose what you want to use.