如何在swift中将字符索引从layoutManager转换为String scale

Posted

技术标签:

【中文标题】如何在swift中将字符索引从layoutManager转换为String scale【英文标题】:How to convert character index from layoutManager to String scale in swift 【发布时间】:2016-06-13 02:50:00 【问题描述】:

如何在 swift 中将字符索引从 layoutManager 转换为 String scale? 这是我正在使用的代码:

let touchPoint: CGPoint = gesture.locationOfTouch(0, inView: self.definitionLabel)
let index = layoutManager.characterIndexForPoint(touchPoint, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

请不要告诉我在字符串字符集的第一个索引上使用 advanceBy() 函数,因为像 ò 这样的字符在 layoutManager 的比例中计为两个,但 swift 字符串将主题计为一次。

【问题讨论】:

【参考方案1】:

NSLayoutManager 返回的索引是“基于NSString”, 即它是从字符串开头开始的 UTF-16 代码单元的数量 到给定点的字符。 (所以ò 实际上算作 一个,但 Emojis ? 算二,而标志 ?? 甚至算四。)

要将该索引转换为有效的 Swift String 索引,您可以使用 与https://***.com/a/30404532/1187415中的方法相同:

let text = ... // the stored text
let i16 = text.utf16.startIndex.advancedBy(index, limit: text.utf16.endIndex)
// i16 is a String.UTF16View.Index
if let strIndex = String.Index(i16, within: text) 
    // strIndex is a String.CharacterView.Index
    let char = text[strIndex]
    print(char)
 

【讨论】:

【参考方案2】:

为 Swift 5 更新

Martin R 的回答给了我大致的轮廓;这是工作中的 Swift 5 版本。我的适用于带有属性文本的 UITextView,但也适用于常规字符串以及 UITextField 和 UILabel。

    func handleTap(_ sender: UIGestureRecognizer) 
        guard let textView = sender.view as? UITextView else  return 

        guard let plaintext = textView.attributedText?.string else  return 
        //guard let plaintext = textView.text else  return 

        let location = sender.location(in: textView)
        let charIndex = textView.layoutManager.characterIndex(for: location, in: textView.textContainer,
                                                          fractionOfDistanceBetweenInsertionPoints: nil)

        if let strIndex = plaintext.utf16.index(plaintext.utf16.startIndex, offsetBy: charIndex, limitedBy: plaintext.utf16.endIndex) 
            let char = plaintext[strIndex]
            print("Character tapped was \(char)")
        
    

    let textTap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    textView.addGestureRecognizer(textTap)

【讨论】:

以上是关于如何在swift中将字符索引从layoutManager转换为String scale的主要内容,如果未能解决你的问题,请参考以下文章

如何从解析中的对象中获取 ObjectId 并在 swift 中将其呈现为字符串

如何在swift中将字符串“One”的字符转换为整数“1”[关闭]

Swift 3 - 如何从包含字符串的索引中读取 json 输出

如何在 Swift 中将 Int 转换为字符

如何在 Swift 中将 NSURL 转换为字符串

如何在Swift中将字符串哈希到SHA512?