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
Author by
Elliot
Updated on September 11, 2020Comments
-
Elliot over 3 years
I have an
NSString
orNSMutableString
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 almost 15 yearsIf 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 almost 15 yearsmy 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 over 14 yearsi have not been able to get this to work at all. I'm trying to count the number of spaces.
-
borrrden over 11 years@lawrence By default, spaces and whitespace are ignored by NSScanner.
-
Bjinse about 10 yearsThis 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 about 10 yearsCreates a temporary array though.. For speed, Jacque's answer should be preferred.
-
Gavin Hope about 10 yearsYou can call
setCharactersToBeSkipped:(NSCharacterSet *)skipSet
withnil
as theskipSet
- and theNSScanner
won't skip any characters. -
meaning-matters over 8 yearsDoes this count a space at the beginning and end of
yourString
? -
Ethan Holshouser over 7 yearsThe speed difference will only matter if you're doing it thousands of times.
-
Cœur over 4 years@Bjinse both of them are typedef to
unsigned short
, so yes. -
Cœur over 4 yearsIt's unclear if you're referring to Abizern post or user251442 post.
-
Cœur over 4 yearsThis won't return
2
, becausescanCharactersFromSet:intoString:
will stop as soon as it doesn't get a match. -
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).