在Swift中查找字符串中第N个子串出现的索引

8
我的Swift应用程序涉及在UITextView中搜索文本。用户可以在该文本视图中搜索某个子字符串,然后跳转到该字符串在文本视图中的任何实例(比如第三个实例)。我需要找出他们所在字符的整数值。
例如:
例1:用户搜索“hello”,文本视图读取“hey hi hello, hey hi hello”,然后用户按向下箭头查看第二个实例。我需要知道第二个hello中第一个h的整数值(即在文本视图中该h所在的#字符)。整数值应为22。
例2:用户在文本视图读取“abcd”时搜索“abc”,并且正在寻找第一个实例,因此整数值应为1(因为它是他们正在搜索的实例的第一个字符的整数值)。
我该如何获得用户正在搜索的字符的索引?

1
这基本上是 http://stackoverflow.com/questions/28685420/search-string-for-repeating-instances-of-a-word 的重复。 - rmaddy
@rmaddy 对我来说很有帮助,但不完全是我在这里询问的。谢谢。 - owlswipe
2
答案通常正是您所需要的。通过传递从第一个子字符串结尾开始的范围,您可以获得第二个子字符串。 - rmaddy
可能是搜索重复单词实例的字符串的重复内容。 - ndmeiri
2个回答

12

Xcode 11 • Swift 5 或更高版本

let sentence = "hey hi hello, hey hi hello"
let query = "hello"
var searchRange = sentence.startIndex..<sentence.endIndex
var indices: [String.Index] = []

while let range = sentence.range(of: query, options: .caseInsensitive, range: searchRange) {
    searchRange = range.upperBound..<searchRange.upperBound
    indices.append(range.lowerBound)
}

print(indices)   // "[7, 21]\n"

[Swift.String.Index(_rawBits: 1), Swift.String.Index(_rawBits: 524288)] - Eduard Streltsov
是的,在 Swift 的演进过程中它有所改变,但仍然是正确的。 - Leo Dabus

5

另一种方法是使用NSRegularExpression,该方法旨在轻松迭代字符串中的匹配项。如果您使用.ignoreMetacharacters选项,则不会应用任何复杂的通配符/正则表达式逻辑,而只会查找所需的字符串。因此,请考虑以下内容:

let string = "hey hi hello, hey hi hello"  // string to search within
let searchString = "hello"                 // string to search for
let matchToFind = 2                        // grab the second occurrence

let regex = try! NSRegularExpression(pattern: searchString, options: [.caseInsensitive, .ignoreMetacharacters])

您可以使用enumerateMatches:
var count = 0
let range = NSRange(string.startIndex ..< string.endIndex, in: string)
regex.enumerateMatches(in: string, range: range) { result, _, stop in
    count += 1
    if count == matchToFind {
        print(result!.range.location)
        stop.pointee = true
    }
}

或者你可以使用 matches(in:range:) 找到它们中的所有内容,然后获取第 n 个:

let matches = regex.matches(in: string, range: range)
if matches.count >= matchToFind {
    print(matches[matchToFind - 1].range.location)
}

显然,如果你愿意的话,可以省略 .ignoreMetacharacters 选项并允许用户执行正则表达式搜索(例如通配符、整个单词搜索、单词开头等)。
对于 Swift 2,请参见 这个答案的先前版本

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接