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 [] } } }