首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从unicode字符符号获取范围。斯威夫特

从unicode字符符号获取范围。斯威夫特
EN

Stack Overflow用户
提问于 2018-06-06 21:13:45
回答 1查看 1.3K关注 0票数 3

我使用textView(_: shouldChangeTextIn: replacementText:)函数来根据情况更改输入数据。我使用范围,但在使用unicode字符符号(例如(͡°͜ʖ͡°) )时,我无法获得Swift范围。请告诉我怎么做?

代码语言:javascript
复制
 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

        let maxLenthNotReached = textView.text.count + (text.count - range.length) <= maxTextLength

        if maxLenthNotReached {
            guard let newRange = Range(range, in: identityString) else { return false }
            identityString = identityString.replacingCharacters(in: newRange, with: text)
        }

        return maxLenthNotReached
    }

Example project

应用程序崩溃示例http://take.ms/ojIJq

更新:我更改了此方法,但在删除时再次崩溃

代码语言:javascript
复制
"entering data" ""
"testString" "༼ つ ͡° ͜ʖ ͡° ༽つ( ͡° ͜ʖ ͡"
"entering data" ""

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    debugPrint("textView.text", textView.text)
    testString = textView.text.replacingCharacters(in: Range(range, in: textView.text)!, with: text)//
    debugPrint("testString", testString)
    return true
}

更新1:我在textView中输入了这些字符

代码语言:javascript
复制
( ͡° ͜ʖ ͡°)༼ つ ͡° ͜ʖ ͡° ༽つ

然后我开始删除带右向左的三个字符后,右边的几个符号被° ༽つ删除了,而车里的emoji已经离开了,那么我就拿不到范围了,因为我放了守卫,应用程序不会崩溃,如果我删除了,当然会有应用程序崩溃。

完整代码

代码语言:javascript
复制
class ViewController: UIViewController {

    // MARK: - IBOutlets
    @IBOutlet private weak var textView: UITextView! {
        didSet {
            textView.delegate = self
            textView.text = "( ͡° ͜ʖ ͡°)༼ つ ͡° ͜ʖ ͡° ༽つ"
        }
    }

    // MARK: - Properties

    private var testString = ""

}


extension ViewController: UITextViewDelegate {

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        guard let newRange = Range(range, in: textView.text) else {
            return false
        }
        testString = textView.text.replacingCharacters(in: newRange, with: text)
        return true
    }

}

更新2:在与Martin交谈后,我发现并提供了一个细节,即这个问题只在键盘上发生,而默认键盘则一切正常。

我的原始行是"( ͡° ͜ʖ ͡°)༼ つ ͡° ͜ʖ ͡° ༽つ”,此行用于example.If我从左到右删除此行,应用程序崩溃,马丁要求在应用程序崩溃前在控制台中显示最新数据,崩溃前的最后一次打印是textView" "( ͡° ͜ʖ ͡°)༼ つ ͡° ͜ʖ ͡" "range" {27, 1}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-08 05:56:15

正如在讨论中所发现的:

  • OP正在使用Google键盘,
  • 文本视图委托方法是通过

textView.text = "(͡°͜ʖ͡°)༼つ͡°͜ʖ͡“range ={ 27,1}

  • ,然后

让newRange =range(范围,单位: textView.text)

返回nil.

原因是范围指向字符的“中间”,该字符存储为UTF-16代理项对。以下是一个简化的自包含示例:

代码语言:javascript
复制
let text = "Hello !"
let range = NSRange(location: 7, length: 1)
let newRange = Range(range, in: text)
print(newRange as Any) // nil   

这看起来像是一个bug (在Google键盘上?)对我来说,但有一个可能的解决办法。

“诀窍”是确定“组合字符序列”的最接近的周围范围,下面是如何做到这一点的(比较From any UTF-16 offset, find the corresponding String.Index that lies on a Character boundary):

代码语言:javascript
复制
extension String {
    func safeRange(from nsRange: NSRange) -> Range<String.Index>? {
        guard nsRange.location >= 0 && nsRange.location <= utf16.count else { return nil }
        guard nsRange.length >= 0 && nsRange.location + nsRange.length <= utf16.count else { return nil }
        let from = String.Index(encodedOffset: nsRange.location)
        let to = String.Index(encodedOffset: nsRange.location + nsRange.length)
        return rangeOfComposedCharacterSequences(for: from..<to)
    }
}

现在

代码语言:javascript
复制
let newRange = textView.text.safeRange(from: range)

返回将整个字符括起来的String范围。在我们的简化示例中:

代码语言:javascript
复制
let text = "Hello !"
let range = NSRange(location: 7, length: 1)
let newRange = text.safeRange(from: range)
print(newRange as Any) // Optional(Range(...))   
print(text.replacingCharacters(in: newRange!, with: "")) // Hello !
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50721378

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档