可靠的函数来获取Swift中字符串中子字符串的位置

twh*_*mon 5 string encoding swift

这对英语很有用:

public static func posOf(needle: String, haystack: String) -> Int {
    return haystack.distance(from: haystack.startIndex, to: (haystack.range(of: needle)?.lowerBound)!)
}
Run Code Online (Sandbox Code Playgroud)

但对于外来字符,返回的值总是太小.例如,"का"被认为是一个单位而不是2个单位.

posOf(needle: "???", haystack: "?? ???? ?? ???? ????? ???? ??? ??? ???? ???") // 21
Run Code Online (Sandbox Code Playgroud)

我后来使用21在NSRange(location:length:)需要28的地方才能NSRange正常工作.

Mar*_*n R 5

Swift StringCharacters 的集合,每个Character 代表一个"扩展的Unicode字形集群".

NSString 是UTF-16代码单元的集合.

例:

print("??".characters.count) // 1
print(("??" as NSString).length) // 2
Run Code Online (Sandbox Code Playgroud)

Swift String范围表示为Range<String.Index>,NSString范围表示为NSRange.

您的函数计算Character从大海捞针开始到针头开始的s 数,这与UTF-16代码点的数量不同.

如果您需要"NSRange兼容"字符数,那么最简单的方法是使用以下 range(of:)方法NSString:

let haystack = "?? ???? ?? ???? ????? ???? ??? ??? ???? ???"
let needle = "???"

if let range = haystack.range(of: needle) {
    let pos = haystack.distance(from: haystack.startIndex, to: range.lowerBound)
    print(pos) // 21
}

let nsRange = (haystack as NSString).range(of: needle)
if nsRange.location != NSNotFound {
    print(nsRange.location) // 31
}
Run Code Online (Sandbox Code Playgroud)

或者,使用utf16Swift字符串的视图来计算UTF-16代码单元:

if let range = haystack.range(of: needle) {
    let lower16 = range.lowerBound.samePosition(in: haystack.utf16)
    let pos = haystack.utf16.distance(from: haystack.utf16.startIndex, to: lower16)
    print(pos) // 31
}
Run Code Online (Sandbox Code Playgroud)

(参见例如 NSRange到范围<String.Index>为多个方法之间进行转换Range<String.Index>NSRange).