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

问题描述 投票:0回答:7

有一个子串在字符串中出现多次。我用的是

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);
iphone ios xcode nsstring substring
7个回答
86
投票

您可以使用

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

6
投票

斯威夫特3.0

查找子字符串的所有位置

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;

这个输出-

enter image description here


2
投票

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

由于 NSRange 是一个结构体,因此不能直接添加到数组中。通过使用 NSValue,我可以先对匹配项进行encode,然后将其添加到数组中。为了检索范围,我将 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;
}

1
投票

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

要消除警告,请放入该组中的枚举

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


1
投票

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

注意:字符串和子字符串都是 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
    }
}

0
投票

我建议使用正则表达式,因为它是一种更具声明性的方式,并且需要编写的代码行更少。

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"%@" options:nil error:nil];
NSString *toSearchStr = @"12312 %@ Text %@ asdsa %@";
__block int occurs = 0;
[regex enumerateMatchesInString:toSearchStr options:0 range:NSMakeRange(0, toSearchStr.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
       occurs++;
}];
// occurs == 3

0
投票

Swift 版本

extension NSString {
    func ranges(of searchString: String, options: NSString.CompareOptions = []) -> [NSRange] {
        let lengthOnce = length
        var searchRange = NSRange(location: 0, length: lengthOnce)
        var result = [NSRange]()
        while true {
            let foundRange = range(of: searchString, options: options, range: searchRange)
            if foundRange.location == NSNotFound {
                break
            } else {
                result.append(foundRange)
                searchRange = NSRange(location: foundRange.upperBound, length: lengthOnce - foundRange.upperBound)
            }
        }
        return result
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.