NSString.rangeOfString returns 非拉丁字符的异常结果

NSString.rangeOfString returns unusual result with non-latin characters

我需要获取字符串中两个单词的范围,例如:

ยัฟิแก ไฟหก

(这实际上是我在输入 PYABCD WASD)- 这是一个毫无意义的测试,因为我不会说泰语。

//Find all the ranges of each word
var words:  [String]    = []
var ranges: [NSRange]   = []

//Convert to nsstring first because otherwise you get stuck with Ranges and Strings.
let nstext = backgroundTextField.stringValue as NSString //contains "ยัฟิแก ไฟหก"
words  = nstext.componentsSeparatedByString(" ")
var nstextLessWordsWeHaveRangesFor = nstext //if you have two identical words this prevents just getting the first word's range

for word in words
        {

            let range:NSRange = nstextLessWordsWeHaveRangesFor.rangeOfString(word)
            Swift.print(range)
            ranges.append(range)

            //create a string the same length as word
            var fillerString:String = ""

            for i in 0..<word.characters.count{
            //for var i=0;i<word.characters.count;i += 1{
                Swift.print("i: \(i)")
               fillerString = fillerString.stringByAppendingString(" ")
            }

            //remove duplicate words / letters so that we get correct range each time. 
            if range.length <= nstextLessWordsWeHaveRangesFor.length
            {
                nstextLessWordsWeHaveRangesFor = nstextLessWordsWeHaveRangesFor.stringByReplacingCharactersInRange(range, withString: fillerString)
            }             
        }

输出:

(0,6)
(5,4)

这些范围重叠。

由于范围不一致,这会导致我在尝试使用 NSLayoutManager.enumerateEnclosingRectsForGlyphRange 时出现问题。

如何获得正确的范围(或在这种特定情况下,非重叠范围)?

删除 nstextLessWordsWeHaveRangesFor 解决了问题(在底部以 range.length <= nstextLessWordsWeHaveRangesFor.length 开头)。该变量的修改正在改变范围并给出意外的输出。下面是去除重复词后的结果:

var words: [String] = []

let nstext = "ยัฟิแก ไฟหก" as NSString
words = nstext.componentsSeparatedByString(" ")

for word in words {
    let range = nstext.rangeOfString(word)
    print(range)
}

输出为:(0,6)(7,4)

Swift String 个字符描述 "extended grapheme clusters",并且 NSString 使用 UTF-16 代码点,因此字符串的长度不同 取决于您使用的表示形式。

比如第一个字符"ยั"其实就是组合 "ย" (U+0E22) 的变音符号 " ั" (U+0E31)。 这算作一个 String 个字符,但算作两个 NSString 个字符。 因此,当您将单词替换为 空间。

最简单的解决方案是坚持一个,StringNSString (如果可能的话)。由于您正在使用 NSString,因此更改

 for i in 0..<word.characters.count {

for i in 0..<range.length {

应该可以解决问题。填充字符串的创建 可以简化为

//create a string the same length as word
let fillerString = String(count: range.length, repeatedValue: Character(" "))