NSString中子字符串的出现次数?

igu*_*222 56 cocoa substring objective-c nsstring

如何获得NSString(例如@"cake")出现在更大的NSString中的次数(例如@"Cheesecake, apple cake, and cherry pie")?

我需要在很多字符串上执行此操作,因此无论使用何种方法都需要相对较快.

谢谢!

Mat*_*hen 98

这没有经过测试,但应该是一个好的开始.

NSUInteger count = 0, length = [str length];
NSRange range = NSMakeRange(0, length); 
while(range.location != NSNotFound)
{
  range = [str rangeOfString: @"cake" options:0 range:range];
  if(range.location != NSNotFound)
  {
    range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
    count++; 
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 是`len = length`? (2认同)

gwd*_*wdp 70

如下所示的正则表达式应该在没有循环交互的情况下完成工作......

编辑

NSString *string = @"Lots of cakes, with a piece of cake.";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"cake" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];
NSLog(@"Found %i",numberOfMatches);
Run Code Online (Sandbox Code Playgroud)

仅适用于iOS 4.x和上级.

  • 即使这种实现更紧凑,使用NSRange循环的接受答案也会更快.在30页的文本文档中进行快速测试时,对单个字的循环搜索需要9ms,而正则表达式实现需要60ms. (6认同)
  • 这应该是公认的答案.老实说,这比for循环要好得多.如果您需要的不仅仅是字符串的第一个或最后一个,请使用RegEx. (2认同)

小智 43

我正在寻找一种比我更好的方法,但这是另一个例子:

NSString *find = @"cake";
NSString *text = @"Cheesecake, apple cake, and cherry pie";

NSInteger strCount = [text length] - [[text stringByReplacingOccurrencesOfString:find withString:@""] length];
strCount /= [find length];
Run Code Online (Sandbox Code Playgroud)

我想知道哪一个更有效.

NSString为更好的用法做了一个类别:

// NSString+CountString.m

@interface NSString (CountString)
- (NSInteger)countOccurencesOfString:(NSString*)searchString;
@end

@implementation NSString (CountString)
- (NSInteger)countOccurencesOfString:(NSString*)searchString {
    NSInteger strCount = [self length] - [[self stringByReplacingOccurrencesOfString:searchString withString:@""] length];
    return strCount / [searchString length];
}
@end
Run Code Online (Sandbox Code Playgroud)

简单地称之为:

[text countOccurencesOfString:find];
Run Code Online (Sandbox Code Playgroud)

可选:您可以通过定义来修改它以搜索不区分大小写 options:


Dav*_*ong 23

有几种方法可以做到.您可以迭代调用rangeOfString:options:range:,或者您可以执行以下操作:

NSArray * portions = [aString componentsSeparatedByString:@"cake"];
NSUInteger cakeCount = [portions count] - 1;
Run Code Online (Sandbox Code Playgroud)

编辑我再次考虑这个问题,我写了一个线性时间算法来进行搜索(线性到干草堆字符串的长度):

+ (NSUInteger) numberOfOccurrencesOfString:(NSString *)needle inString:(NSString *)haystack {
    const char * rawNeedle = [needle UTF8String];
    NSUInteger needleLength = strlen(rawNeedle);

    const char * rawHaystack = [haystack UTF8String];
    NSUInteger haystackLength = strlen(rawHaystack);

    NSUInteger needleCount = 0;
    NSUInteger needleIndex = 0;
    for (NSUInteger index = 0; index < haystackLength; ++index) {
        const char thisCharacter = rawHaystack[index];
        if (thisCharacter != rawNeedle[needleIndex]) {
            needleIndex = 0; //they don't match; reset the needle index
        }

        //resetting the needle might be the beginning of another match
        if (thisCharacter == rawNeedle[needleIndex]) {
            needleIndex++; //char match
            if (needleIndex >= needleLength) {
                needleCount++; //we completed finding the needle
                needleIndex = 0;
            }
        }
    }

    return needleCount;
}
Run Code Online (Sandbox Code Playgroud)

  • @Matthew是的,但这是一个双线解决方案. (7认同)
  • componentsSeparatedByString解决方案会导致大量不必要的内存分配. (3认同)

Das*_*ash 11

更快速的键入,但可能效率较低的解决方案.

- (int)numberOfOccurencesOfSubstring:(NSString *)substring inString:(NSString*)string
{
    NSArray *components = [string componentsSeparatedByString:substring];
    return components.count-1; // Two substring will create 3 separated strings in the array.
}
Run Code Online (Sandbox Code Playgroud)

  • 必须是"components.count-1;" (2认同)