Número de Ocorrências de um Caractere no NSString

Eu tenho um NSString ou NSMutableString e gostaria de obter o número de ocorrências de um caractere específico.

Eu preciso fazer isso para alguns caracteres – caracteres ingleses maiúsculos neste caso – então seria bom que fosse rápido.

replaceOccurrencesOfString:withString:options:range: retornará o número de caracteres substituídos em um NSMutableString .

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

Você pode fazer isso em uma linha. Por exemplo, isso conta o número de espaços:

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

Experimente esta categoria no 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 

Este é aproximadamente 5 vezes mais rápido que a abordagem componentsSeparatedByString:

Sempre que você estiver procurando por coisas em um NSString , tente usar o NSScanner primeiro.

 NSString *yourString = @"ABCCDEDRFFED"; // For example NSScanner *scanner = [NSScanner scannerWithString:yourString]; NSCharacterSet *charactersToCount = @"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]; 

Hoje em dia a primeira coisa que vem à minha mente para algo assim: NSCountedSet

 NSString *string =@"AAATTC"; NSMutableArray *array = [@[] mutableCopy]; [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 

Sua solução não funcionou para mim, eu adicionei uma condição no loop para incrementar numberOfChar somente se mainScanner atingiu o final da string:

 NSString *yourString = @"ABCCDEDRFFED"; // For example NSScanner *mainScanner = [NSScanner scannerWithString:yourString]; NSString *temp; NSInteger numberOfChar=0; while(![mainScanner isAtEnd]) { [mainScanner scanUpToString:@"C" intoString:&temp]; if(![mainScanner isAtEnd]) { numberOfChar++; [mainScanner scanString:@"C" intoString:nil]; } } 

Note que esta é uma solução rápida, não tenho tempo para fazer uma solução elegante …

Eu provavelmente usaria

NSString rangeOfCharacterFromSet:

ou

rangeOfCharacterFromSet:options:range::

onde o conjunto é o conjunto de caracteres que você está procurando. Ele retorna com a localização do primeiro caractere correspondente ao conjunto. Mantenha array ou dictionary e incremente a contagem para caractere, depois repita.

O exemplo com o scanner estava caindo no iPhone. Eu encontrei esta solução:

 NSString *yourString = @"ABCCDEDRFFED"; // For example NSScanner *mainScanner = [NSScanner scannerWithString:yourString]; NSString *temp; NSInteger numberOfChar=0; while(![mainScanner isAtEnd]) { [mainScanner scanUpToString:@"C" intoString:&temp]; numberOfChar++; [mainScanner scanString:@"C" intoString:nil]; } 

Funcionou para mim sem falhar. Espero que possa ajudar!

Aqui está uma versão de trabalho do Swift 3, para NSRange, Range, String e NSString! Apreciar 🙂

 /// All ranges using NSString and NSRange /// Is usually used together with NSAttributedString extension NSString { public func ranges(of searchString: String, options: CompareOptions = .literal, searchRange: NSRange? = nil) -> [NSRange] { let searchRange = searchRange ?? NSRange(location: 0, length: self.length) let subRange = range(of: searchString, options: options, range: searchRange) if subRange.location != NSNotFound { let nextRangeStart = subRange.location + subRange.length let nextRange = NSRange(location: nextRangeStart, length: searchRange.location + searchRange.length - nextRangeStart) return [subRange] + ranges(of: searchString, options: options, searchRange: nextRange) } else { return [] } } } /// All ranges using String and Range /// Is usually used together with NSAttributedString extension String { public func ranges(of searchString: String, options: CompareOptions = [], searchRange: Range? = nil ) -> [Range] { if let range = range(of: searchString, options: options, range: searchRange, locale: nil) { let nextRange = range.upperBound..<(searchRange?.upperBound ?? endIndex) return [range] + ranges(of: searchString, searchRange: nextRange) } else { return [] } } }