xcode 在 NSString 中查找子字符串的所有位置(不仅仅是第一个)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7033574/
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-14 21:43:14  来源:igfitidea点击:

Find all locations of substring in NSString (not just first)

iphoneiosxcodensstringsubstring

提问by forest

There is a substring that occurs in a string several times. I use rangeOfString, but it seems that it can only find the first location. How can I find all the locations of the substring?

有一个子串在一个字符串中出现多次。我用rangeOfString,但似乎只能找到第一个位置。如何找到子字符串的所有位置?

NSString *subString1 = @"</content>";
NSString *subString2 = @"--\n";
NSRange range1 = [newresults rangeOfString:subString1];
NSRange range2 = [newresults rangeOfString:subString2];
int location1 = range1.location;
int location2 = range2.location;
NSLog(@"%i",location1);
NSLog(@"%i",location2);

回答by PengOne

You can use rangeOfString:options:range:and set the third argument to be beyond the range of the first occurrence. For example, you can do something like this:

您可以使用rangeOfString:options:range:并将第三个参数设置为超出第一次出现的范围。例如,您可以执行以下操作:

NSRange searchRange = NSMakeRange(0,string.length);
NSRange foundRange;
while (searchRange.location < string.length) {
    searchRange.length = string.length-searchRange.location;
    foundRange = [string rangeOfString:substring options:0 range:searchRange];
    if (foundRange.location != NSNotFound) {
        // found an occurrence of the substring! do stuff here
        searchRange.location = foundRange.location+foundRange.length;
    } else {
        // no more substring to find
        break;
    }
}

回答by Abhishek Jain

Swift 3.0

斯威夫特 3.0

Find all locations of substring i

查找子串的所有位置 i

let text = "This is the text and i want to replace something"
let mutableAttributedString = NSMutableAttributedString(string: text)

var searchRange = NSRange(location: 0, length: text.characters.count)
var foundRange = NSRange()
while searchRange.location < text.characters.count {
    searchRange.length = text.characters.count - searchRange.location
    foundRange = (text as NSString).range(of: "i", options: NSString.CompareOptions.caseInsensitive, range: searchRange)
    if foundRange.location != NSNotFound {
        // found an occurrence of the substring! do stuff here
        searchRange.location = foundRange.location + foundRange.length
        mutableAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: foundRange)
    }
    else {
        // no more substring to find
        break
    }
}

//Apply
textLabel.attributedText = mutableAttributedString;

And this output-

而这个输出——

enter image description here

在此处输入图片说明

回答by titusmagnus

This is my solution. Basically, the algorithm traverses the string looking for substring matches and returns those matches in an array.

这是我的解决方案。基本上,该算法遍历字符串以查找子字符串匹配项并在数组中返回这些匹配项。

Since an NSRangeis a struct it cannot be added to the array directly. By using NSValue, I can encodethe match first and then add it to the array. To retrieve the range, I then decodethe NSValueobject to an NSRange.

由于NSRange是一个结构体,因此不能直接添加到数组中。通过使用NSValue,我可以先匹配进行编码,然后将其添加到数组中。为了检索范围,我将NSValue对象解码NSRange

#import <Foundation/Foundation.h>

NSRange makeRangeFromIndex(NSUInteger index, NSUInteger length) {
    return NSMakeRange(index, length - index);
}

NSArray<NSValue *> * allLocationsOfStringMatchingSubstring(NSString *text, NSString *pattern) {
    NSMutableArray *matchingRanges = [NSMutableArray new];
    NSUInteger textLength = text.length;
    NSRange match = makeRangeFromIndex(0, textLength);

    while(match.location != NSNotFound) {
        match = [text rangeOfString:pattern options:0L range:match];
        if (match.location != NSNotFound) {
            NSValue *value = [NSValue value:&match withObjCType:@encode(NSRange)];
            [matchingRanges addObject:value];
            match = makeRangeFromIndex(match.location + 1, textLength);
        }
    }

    return [matchingRanges copy];
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *text = @"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG";
        NSString *pattern = @"CAT";
        NSArray<NSValue *> *matches = allLocationsOfStringMatchingSubstring(text, pattern);

        NSLog(@"Text: %@", text);
        NSLog(@"Pattern: %@", pattern);
        NSLog(@"Number of matches found: %li", matches.count);

        [matches enumerateObjectsUsingBlock:^(NSValue *obj, NSUInteger idx, BOOL *stop) {
            NSRange match;
            [obj getValue:&match];
            NSLog(@"   Match found at index: %li", match.location);
        }];
    }
    return 0;
}

回答by Gibtang

Passing nil to [string rangeOfString:substring options:nil range:searchRange];shows a warning.

将 nil 传递给[string rangeOfString:substring options:nil range:searchRange]; 显示警告。

To get rid of the warning, put in an enum from this group

要摆脱警告,请放入来自该组的枚举

enum {
   NSCaseInsensitiveSearch = 1,
   NSLiteralSearch = 2,
   NSBackwardsSearch = 4,
   NSAnchoredSearch = 8,
   NSNumericSearch = 64,
   NSDiacriticInsensitiveSearch = 128,
   NSWidthInsensitiveSearch = 256,
   NSForcedOrderingSearch = 512,
   NSRegularExpressionSearch = 1024
};

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/doc/constant_group/Search_and_Comparison_Options

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/doc/constant_group/Search_and_Comparison_Options

回答by bwait

Here is a version in Swift 2.2 of PengOne's answer with input from kevinlawler and Gibtang

这是 PengOne 答案的 Swift 2.2 版本,其中包含来自 kevinlawler 和 Gibtang 的输入

Note: string and substring are of type NSString

注意:string 和 substring 是 NSString 类型

let fullStringLength = (string as String).characters.count
var searchRange = NSMakeRange(0, fullStringLength)
while searchRange.location < fullStringLength {
    searchRange.length = fullStringLength - searchRange.location
    let foundRange = string.rangeOfString(substring as String, options: .CaseInsensitiveSearch, range: searchRange)
    if foundRange.location != NSNotFound {
        // found an occurrence of the substring! do stuff here
        searchRange.location = foundRange.location + 1
    } else {
        // no more strings to find
        break
    }
}