2

I have a string like @"1234123412341234", i need to append space between every 4 chars like.

@"1234 1234 1234 1234"

i.e, I need a NSString like Visa Card Type. I have tried like this but i didn't get my result.

-(void)resetCardNumberAsVisa:(NSString*)aNumber
{
  NSMutableString *s = [aNumber mutableCopy];

  for(int p=0; p<[s length]; p++)
  {
    if(p%4==0)
    {
        [s insertString:@" " atIndex:p];
    }
  }
  NSLog(@"%@",s);
}
Harish
  • 2,496
  • 4
  • 24
  • 48
  • possible duplicate of [Formatting a UITextField for credit card input like (xxxx xxxx xxxx xxxx)](http://stackoverflow.com/questions/12083605/formatting-a-uitextfield-for-credit-card-input-like-xxxx-xxxx-xxxx-xxxx) – Szu Sep 30 '14 at 08:42
  • 1
    Do you want to format it on the fly while editing it on a `UITextField` or you have the full number and want to insert whitespaces in it? – DeFrenZ Sep 30 '14 at 09:10

6 Answers6

7

Here's a unicode aware implementation as a category on NSString:

@interface NSString (NRStringFormatting)
- (NSString *)stringByFormattingAsCreditCardNumber;
@end

@implementation NSString (NRStringFormatting)
- (NSString *)stringByFormattingAsCreditCardNumber
{
    NSMutableString *result = [NSMutableString string];
    __block NSInteger count = -1;
    [self enumerateSubstringsInRange:(NSRange){0, [self length]}
                             options:NSStringEnumerationByComposedCharacterSequences
                          usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                              if ([substring rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound)
                                  return;
                              count += 1;
                              if (count == 4) {
                                  [result appendString:@" "];
                                  count = 0;
                              }
                              [result appendString:substring];
                          }];
    return result;
}
@end

Try it with this test string:

NSString *string = @"ab  132487 387  e e e ";
NSLog(@"%@", [string stringByFormattingAsCreditCardNumber]);

The method works with non-BMP characters (i.e. emoji) and handles existing white space.

Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
6

Your code is pretty close, however a better semantic for the method is to return a new NSString for any given input string:

-(NSString *)formatStringAsVisa:(NSString*)aNumber
{
    NSMutableString *newStr = [NSMutableString new];
    for (NSUInteger i = 0; i < [aNumber length]; i++)
    {
        if (i > 0 && i % 4 == 0)
           [newStr appendString:@" "];
        unichar c = [aNumber characterAtIndex:i];
        [newStr appendString:[[NSString alloc] initWithCharacters:&c length:1]];
    }
    return newStr;
}
Droppy
  • 9,691
  • 1
  • 20
  • 27
  • What is that newString?? – Harish Sep 30 '14 at 08:41
  • awesome man, thanks a lot worked. You saved my life.. ACCEPTED – Harish Sep 30 '14 at 08:44
  • @HarishSaran OK cool, however note that in terms of performance it's a bit expensive as `NSMutableString` doesn't have an `appendCharacter` method so you have to create a string from a single character in order to append. A better implementation would use an array of `unichar` characters as as temporary buffer, however that was too much aggro for me just for this question. – Droppy Sep 30 '14 at 08:47
5

You should do like this:

- (NSString *)resetCardNumberAsVisa:(NSString*)originalString {
    NSMutableString *resultString = [NSMutableString string];

    for(int i = 0; i<[originalString length]/4; i++)
    {
        NSUInteger fromIndex = i * 4;
        NSUInteger len = [originalString length] - fromIndex;
        if (len > 4) {
            len = 4;
        }

        [resultString appendFormat:@"%@ ",[originalString substringWithRange:NSMakeRange(fromIndex, len)]];
    }
    return resultString;
}

UPDATE:

You code will be right on the first inserting space charactor:

This is your originalString:

Text:     123412341234
Location: 012345678901

Base on your code, on the first you insert space character, you will insert at "1" (with location is 4)

And after that, your string is:

Text:     1234 12341234
Location: 0123456789012

So, you see it, now you have to insert second space charater at location is 9 (9%4 != 0)

Hope you can fix your code by yourself!

Tony
  • 4,311
  • 26
  • 49
1

The code snippet from here do what do you want:

- (NSString *)insertSpacesEveryFourDigitsIntoString:(NSString *)string
              andPreserveCursorPosition:(NSUInteger *)cursorPosition 
{
    NSMutableString *stringWithAddedSpaces = [NSMutableString new];
    NSUInteger cursorPositionInSpacelessString = *cursorPosition;
    for (NSUInteger i=0; i<[string length]; i++) {
        if ((i>0) && ((i % 4) == 0)) {
            [stringWithAddedSpaces appendString:@" "];
            if (i < cursorPositionInSpacelessString) {
                (*cursorPosition)++;
            }
        }
        unichar characterToAdd = [string characterAtIndex:i];
        NSString *stringToAdd = 
            [NSString stringWithCharacters:&characterToAdd length:1];

        [stringWithAddedSpaces appendString:stringToAdd];
    }

    return stringWithAddedSpaces;
}
Community
  • 1
  • 1
Szu
  • 2,254
  • 1
  • 21
  • 37
0

swift3 based on Droppy

func codeFormat(_ code: String) -> String {
    let newStr = NSMutableString()
    for i in 0..<code.characters.count {
        if (i > 0 && i % 4 == 0){
            newStr.append(" ")
        }
            var c = (code as NSString).character(at: i)
            newStr.append(NSString(characters: &c, length: 1) as String)
    }
    return newStr as String
}
0

Please make sure that your string length should times by 4.
This solution will insert on the right hand side first.

- (NSString*) fillWhiteGapWithString:(NSString*)source
{
    NSInteger dl = 4;
    NSMutableString* result = [NSMutableString stringWithString:source];
    for(NSInteger cnt = result.length - dl ; cnt > 0 ; cnt -= dl)
    {
        [result insertString:@" " atIndex:cnt];
    }
    return result;
}
Wanpaya
  • 49
  • 6