NSString中字符的出现次数

Ell*_*iot 36 string cocoa cocoa-touch character nsstring

我有一个NSString或者NSMutableString想要获得特定角色的出现次数.

我需要为很多字符做这个 - 在这种情况下是大写的英文字符 - 所以它很快就会很好.

gba*_*aor 100

您可以在一行中执行此操作.例如,这会计算空格数:

NSUInteger numberOfOccurrences = [[yourString componentsSeparatedByString:@" "] count] - 1;
Run Code Online (Sandbox Code Playgroud)

  • 虽然创建一个临时数组..为了速度,[Jacque的答案](http://stackoverflow.com/a/15947190/482601)应该是首选. (7认同)

Jac*_*que 25

在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
Run Code Online (Sandbox Code Playgroud)

这个componentsSeparatedByString:方法比方法快约5倍.


Cyn*_*ing 16

replaceOccurrencesOfString:withString:options:range:将返回a中替换的字符数NSMutableString.

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


Abi*_*ern 7

无论何时在寻找a中的东西NSString,请先尝试使用NSScanner.

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];
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用`nil`作为`skipSet`来调用`setCharactersToBeSkipped:(NSCharacterSet*)skipSet`,并且`NSScanner`不会跳过任何字符. (4认同)
  • @lawrence默认情况下,NSScanner会忽略空格和空格. (3认同)

Vik*_*ica 6

现在,我想到的第一件事就是: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);
}
Run Code Online (Sandbox Code Playgroud)

日志:

C: 1
G: 0
A: 3
T: 2
Run Code Online (Sandbox Code Playgroud)


Cœu*_*œur 5

不同 Objective-C 解决方案的性能比较。

假设以下所有方法都是 NSString 扩展(内部@implementation NSString (CountOfOccurrences))。

作为示例,我使用了一个随机生成的长度为 100000000 的字符串,其中使用所有拉丁字符(CharacterSet(charactersIn: "\u{0020}"..."\u{036F}")在 Swift 中)。要计算的字符是@"a"

在模拟器上的 Xcode 10.3 上以发布配置进行测试。

快速解决方案(精确的逐个字符等效)

有两种方法来计算字符:使用NSLiteralSearch或不使用。计数会不同,性能会受到根本性影响。为了获得最快的结果,我们将执行精确的逐个字符等效。以下四种解决方案给出了非常接近的性能结果。

1. 最快的解决方案:改编自 CynicismRising 答案。

使用replaceOccurrencesOfString:withString:options:range:。这是所有场景中最快的解决方案:即使您替换NSLiteralSearchkNilOptions,您仍然比 pierrot3887 扫描仪解决方案更快。

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    return [[NSMutableString stringWithString:self] replaceOccurrencesOfString:stringToFind
                                                                    withString:stringToFind
                                                                       options:NSLiteralSearch
                                                                         range:NSMakeRange(0, self.length)];
}
Run Code Online (Sandbox Code Playgroud)

2. 第二快,CynicismRising 答案的另一个改编。

使用stringByReplacingOccurrencesOfString:withString:options:range:

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    NSString *strippedString = [self stringByReplacingOccurrencesOfString:stringToFind
                                                               withString:@""
                                                                  options:NSLiteralSearch
                                                                    range:NSMakeRange(0, self.length)];
    return (self.length - strippedString.length) / stringToFind.length;
}
Run Code Online (Sandbox Code Playgroud)

3. 第三快,雅克解决方案。

使用CFStringGetCharacterFromInlineBuffer。请参阅/sf/answers/1116303331/

4. 第四快,我的 Swift 答案到 Objective-C的转换。

使用rangeOfString:options:range:

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    //assert(stringToFind.length);
    NSUInteger count = 0;
    NSRange searchRange = NSMakeRange(0, self.length);
    NSRange foundRange;
    while ((void)(foundRange = [self rangeOfString:stringToFind options:NSLiteralSearch range:searchRange]), foundRange.length) {
        count += 1;
        NSUInteger loc = NSMaxRange(foundRange);
        searchRange = NSMakeRange(loc, self.length - loc);
    }
    return count;
}
Run Code Online (Sandbox Code Playgroud)

缓慢的解决方案

以下解决方案不使用NSLiteralSearch也不执行精确的逐字符等效。前两个可能比快速解决方案慢 10 倍,最后一个可能慢 100 倍。

5.慢解决方案:改编pierrot3887答案

使用scanUpToString:intoString:。遗憾的是,它NSScanner没有提供精确的逐个字符等效的选项。

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    NSScanner *scanner = [NSScanner scannerWithString:self];
    scanner.charactersToBeSkipped = nil;
    scanner.caseSensitive = YES;
    NSUInteger numberOfOccurrences = 0;
    while (!scanner.isAtEnd) {
        [scanner scanUpToString:stringToFind intoString:nil];
        if (!scanner.isAtEnd) {
            numberOfOccurrences++;
            [scanner scanString:stringToFind intoString:nil];
        }
    }
    return numberOfOccurrences;
}
Run Code Online (Sandbox Code Playgroud)

6. 较慢的解决方案:gbaor解决方案

使用componentsSeparatedByString:。关于单行可行的论点,请注意,上面给出的最快解决方案也是单行。

- (NSUInteger)countOccurrencesOfString:(NSString *)stringToFind
{
    return [self componentsSeparatedByString:stringToFind].count - 1;
}
Run Code Online (Sandbox Code Playgroud)

7. 最慢的解决方案:改编 vikingosegundo 答案

使用enumerateSubstringsInRange:options:usingBlock:

- (NSUInteger)countOccurrencesOfCharacter:(NSString *)characterToFind
{
    __block NSUInteger counter = 0;
    [self enumerateSubstringsInRange:NSMakeRange(0, self.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        if ([characterToFind isEqualToString:substring]) counter += 1;
    }];
    return counter;
}
Run Code Online (Sandbox Code Playgroud)