Number of Occurrences of a Character in NSString

35,698

Solution 1

replaceOccurrencesOfString:withString:options:range: will return the number of characters replaced in a NSMutableString.

[string replaceOccurrencesOfString:@"A" 
                        withString:@"B" 
                           options:NSLiteralSearch 
                             range:NSMakeRange(0, [receiver length])];

Solution 2

You can do this in one line. For example, this counts the number of spaces:

NSUInteger numberOfOccurrences = [[yourString componentsSeparatedByString:@" "] count] - 1;

Solution 3

Try this category on NSString:

@implementation NSString (OccurrenceCount)

- (NSUInteger)occurrenceCountOfCharacter:(UniChar)character
{
    CFStringRef selfAsCFStr = (__bridge CFStringRef)self;

    CFStringInlineBuffer inlineBuffer;
    CFIndex length = CFStringGetLength(selfAsCFStr);
    CFStringInitInlineBuffer(selfAsCFStr, &inlineBuffer, CFRangeMake(0, length));

    NSUInteger counter = 0;

    for (CFIndex i = 0; i < length; i++) {
        UniChar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i);
        if (c == character) counter += 1;
    }

    return counter;
}

@end

This one is approximately 5 times faster than the componentsSeparatedByString: approach.

Solution 4

Whenever you are looking for things in a NSString, try using NSScanner first.

NSString *yourString = @"ABCCDEDRFFED"; // For example
NSScanner *scanner = [NSScanner scannerWithString:yourString];

NSCharacterSet *charactersToCount = [NSCharacterSet characterSetWithCharactersInString:@"C"]; // For example
NSString *charactersFromString;

if (!([scanner scanCharactersFromSet:charactersToCount 
                          intoString:&charactersFromString])) {
    // No characters found
    NSLog(@"No characters found");
}

// should return 2 for this
NSInteger characterCount = [charactersFromString length];

Solution 5

Nowadays the first thing that come to my mind for something like that: NSCountedSet

NSString *string = @"AAATTC";

NSMutableArray *array = [NSMutableArray array];

[string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
    [array addObject:substring];
}] ;
NSCountedSet * set = [[NSCountedSet alloc] initWithArray:array];

for (NSString *nucleobase in @[@"C", @"G", @"A", @"T"]){
    NSUInteger count = [set countForObject:nucleobase];
    NSLog(@"%@: %lu", nucleobase, (unsigned long)count);
}

logs:

C: 1
G: 0
A: 3
T: 2
Share:
35,698
Elliot
Author by

Elliot

Updated on September 11, 2020

Comments

  • Elliot
    Elliot over 3 years

    I have an NSString or NSMutableString and would like to get the number of occurrences of a particular character.

    I need to do this for quite a few characters -- uppercase English characters in this case -- so it would be nice for it to be quick.

  • Elliot
    Elliot almost 15 years
    If I'm understanding the Documentation correctly, this would give the range of any of the characters in the set. But I need the count of each character.
  • Nubzor
    Nubzor almost 15 years
    my idea is to keep dictionary of char -> count pairs and then get the char at given index and increment it's count in dictionary ... or you could just iterate over the string and check if each character is in your set, if it is then increment it's count
  • lawrence
    lawrence over 14 years
    i have not been able to get this to work at all. I'm trying to count the number of spaces.
  • borrrden
    borrrden over 11 years
    @lawrence By default, spaces and whitespace are ignored by NSScanner.
  • Bjinse
    Bjinse about 10 years
    This category works fine, but I have a question: can you use both UniChar (from CFString.h) and unichar (from NSString) as being the same?
  • fabian789
    fabian789 about 10 years
    Creates a temporary array though.. For speed, Jacque's answer should be preferred.
  • Gavin Hope
    Gavin Hope about 10 years
    You can call setCharactersToBeSkipped:(NSCharacterSet *)skipSet with nil as the skipSet - and the NSScanner won't skip any characters.
  • meaning-matters
    meaning-matters over 8 years
    Does this count a space at the beginning and end of yourString?
  • Ethan Holshouser
    Ethan Holshouser over 7 years
    The speed difference will only matter if you're doing it thousands of times.
  • Cœur
    Cœur over 4 years
    @Bjinse both of them are typedef to unsigned short, so yes.
  • Cœur
    Cœur over 4 years
    It's unclear if you're referring to Abizern post or user251442 post.
  • Cœur
    Cœur over 4 years
    This won't return 2, because scanCharactersFromSet:intoString: will stop as soon as it doesn't get a match.
  • Cœur
    Cœur over 4 years
    @EthanHolshouser actually depends on the length of the string. And from my tests, a variation of CynicismRising answer is the fastest (see my answer for details).