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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2166809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:51:48  来源:igfitidea点击:

Number of occurrences of a substring in an NSString?

objective-ccocoansstringsubstring

提问by igul222

How can I get the number of times an NSString (for example, @"cake") appears in a larger NSString (for example, @"Cheesecake, apple cake, and cherry pie")?

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

I need to do this on a lot of strings, so whatever method I use would need to be relatively fast.

我需要在很多字符串上执行此操作,因此我使用的任何方法都需要相对较快。

Thanks!

谢谢!

回答by Matthew Flaschen

This isn't tested, but should be a good start.

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

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

回答by gwdp

A regex like the one below should do the job without a loop interaction...

像下面这样的正则表达式应该可以在没有循环交互的情况下完成工作......

Edited

已编辑

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);

Only available on iOS 4.x and superiors.

仅适用于 iOS 4.x 及更高版本。

回答by igul222

was searching for a better method then mine but here's another example:

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

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

NSInteger strCount = [text length] - [[text stringByReplacingOccurrencesOfString:find withString:@""] length];
strCount /= [find length];

I would like to know which one is more effective.

我想知道哪个更有效。

And I made an NSStringcategory for better usage:

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

simply call it by:

只需通过以下方式调用它:

[text countOccurencesOfString:find];

Optional: you can modify it to search case insensitive by defining options:

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

回答by Dave DeLong

There are a couple ways you could do it. You could iteratively call rangeOfString:options:range:, or you could do something like:

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

NSArray * portions = [aString componentsSeparatedByString:@"cake"];
NSUInteger cakeCount = [portions count] - 1;

EDITI was thinking about this question again and I wrote a linear-time algorithm to do the searching (linear to the length of the haystack string):

编辑我又在考虑这个问题,我写了一个线性时间算法来进行搜索(与 haystack 字符串的长度成线性关系):

+ (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;
}

回答by Dash

A quicker to type, but probably less efficient solution.

输入速度更快,但效率可能较低的解决方案。

- (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.
}

回答by paulmelnikow

Here's another version as a category on NSString:

这是作为 NSString 类别的另一个版本:

-(NSUInteger) countOccurrencesOfSubstring:(NSString *) substring {
    if ([self length] == 0 || [substring length] == 0)
        return 0;

    NSInteger result = -1;
    NSRange range = NSMakeRange(0, 0);
    do {
        ++result;
        range = NSMakeRange(range.location + range.length,
                            self.length - (range.location + range.length));
        range = [self rangeOfString:substring options:0 range:range];
    } while (range.location != NSNotFound);
    return result;
}

回答by riik

Swift solution would be:

Swift 的解决方案是:

var numberOfSubstringAppearance = 0
let length = count(text)
var range: Range? = Range(start: text.startIndex, end: advance(text.startIndex, length))

while range != nil {

    range = text.rangeOfString(substring, options: NSStringCompareOptions.allZeros, range: range, locale: nil)

    if let rangeUnwrapped = range {

        let remainingLength = length - distance(text.startIndex, rangeUnwrapped.endIndex)
        range = Range(start: rangeUnwrapped.endIndex, end: advance(rangeUnwrapped.endIndex, remainingLength))
        numberOfSubstringAppearance++
     }
}

回答by Chris Johnsen

Here is a version done as an extension to NSString(same idea as Matthew Flaschen's answer):

这是一个作为扩展完成的版本NSString(与 Matthew Flaschen 的回答相同的想法):

@interface NSString (my_substr_search)
- (unsigned) countOccurencesOf: (NSString *)subString;
@end
@implementation NSString (my_substring_search)
- (unsigned) countOccurencesOf: (NSString *)subString {
    unsigned count = 0;
    unsigned myLength = [self length];
    NSRange uncheckedRange = NSMakeRange(0, myLength);
    for(;;) {
        NSRange foundAtRange = [self rangeOfString:subString
                                           options:0
                                             range:uncheckedRange];
        if (foundAtRange.location == NSNotFound) return count;
        unsigned newLocation = NSMaxRange(foundAtRange); 
        uncheckedRange = NSMakeRange(newLocation, myLength-newLocation);
        count++;
    }
}
@end
<somewhere> {
    NSString *haystack = @"Cheesecake, apple cake, and cherry pie";
    NSString *needle = @"cake";
    unsigned count = [haystack countOccurencesOf: needle];
    NSLog(@"found %u time%@", count, count == 1 ? @"" : @"s");
}

回答by Peter Hosey

If you want to count words, not just substrings, then use CFStringTokenizer.

如果你想计算words,而不仅仅是子字符串,那么使用CFStringTokenizer

回答by user278859

Matthew Flaschen's answer was a good start for me. Here is what I ended up using in the form of a method. I took a slightly different approach to the loop. This has been tested with empty strings passed to stringToCount and text and with the stringToCount occurring as the first and/or last characters in text.

Matthew Flaschen 的回答对我来说是一个好的开始。这是我最终以方法的形式使用的内容。我对循环采取了稍微不同的方法。这已经通过传递给 stringToCount 和 text 的空字符串以及 stringToCount 作为文本中的第一个和/或最后一个字符进行了测试。

I use this method regularly to count paragraphs in the passed text (ie. stringToCount = @"\r").

我经常使用此方法来计算传递文本中的段落数(即 stringToCount = @"\r")。

Hope this of use to someone.

希望这对某人有用。

    - (int)countString:(NSString *)stringToCount inText:(NSString *)text{
        int foundCount=0;
        NSRange range = NSMakeRange(0, text.length);
        range = [text rangeOfString:stringToCount options:NSCaseInsensitiveSearch range:range locale:nil];
        while (range.location != NSNotFound) {
            foundCount++;
            range = NSMakeRange(range.location+range.length, text.length-(range.location+range.length));
            range = [text rangeOfString:stringToCount options:NSCaseInsensitiveSearch range:range locale:nil];
        }

        return foundCount;
   }

Example call assuming the method is in a class named myHelperClass...

假设该方法位于名为 myHelperClass 的类中的示例调用...

int foundCount = [myHelperClass countString:@"n" inText:@"Now is the time for all good men to come to the aid of their country"];