web-dev-qa-db-fra.com

Nombre d'occurrences d'un personnage dans NSString

J'ai un NSString ou un NSMutableString et j'aimerais connaître le nombre d'occurrences d'un personnage en particulier.

J'ai besoin de faire cela pour pas mal de caractères - des majuscules anglaises dans ce cas - donc ce serait bien que ce soit rapide.

33
Elliot

replaceOccurrencesOfString:withString:options:range: retournera le nombre de caractères remplacés dans une NSMutableString.

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

Vous pouvez le faire en une seule ligne. Par exemple, cela compte le nombre d'espaces:

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

Essayez cette catégorie sur 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

Celui-ci est environ 5 fois plus rapide que l'approche componentsSeparatedByString:.

24
Jacque

Lorsque vous recherchez des éléments dans une NSString, essayez d'abord d'utiliser NSScanner.

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];
8
Abizern

De nos jours, la première chose qui me vienne à l’esprit pour quelque chose comme ça: 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);
}

journaux:

C: 1
G: 0
A: 3
T: 2
6
vikingosegundo

Votre solution ne fonctionnant pas pour moi, j'ai ajouté une condition dans la boucle pour incrémenter numberOfChar uniquement si mainScanner a atteint la fin de la chaîne:

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

Notez que c'est une solution rapide, je n'ai pas le temps de faire une solution élégante ...

2
pierrot3887

L'exemple avec le scanner se brisait sur l'iPhone. J'ai trouvé cette solution: 

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

Cela a fonctionné pour moi sans crash. J'espère que ça peut aider!

1
user251442

J'utiliserais probablement

NSString rangeOfCharacterFromSet:

ou

rangeOfCharacterFromSet:options:range::

où le jeu est le jeu de caractères que vous recherchez. Il retourne avec l'emplacement du premier caractère correspondant à l'ensemble. Conservez le tableau ou le dictionnaire et incrémentez le nombre de caractères, puis répétez l'opération.

1
stefanB

Voici une version de travail Swift 3, pour NSRange, Range, String et NSString! Prendre plaisir :)

/// 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<Index>
/// Is usually used together with NSAttributedString

extension String {
    public func ranges(of searchString: String, options: CompareOptions = [], searchRange: Range<Index>? = nil ) -> [Range<Index>] {
        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 []
        }
    }
}
0
txaidw