[英]Get range from unicode character symbols. Swift
I use textView(_: shouldChangeTextIn: replacementText:)
function to change the input data depending on the situation. 我使用
textView(_: shouldChangeTextIn: replacementText:)
函数根据情况更改输入数据。 I use range, but I can not get the Swift Range when using unicode character symbols (eg ( ͡° ͜ʖ ͡°) ). 我使用范围,但使用Unicode字符符号(例如(͡°͜ʖ͡°) )时无法获得Swift Range。 Please, tell me how it can be done?
请告诉我该怎么做?
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
}
An app crash example http://take.ms/ojIJq 应用崩溃示例http://take.ms/ojIJq
Update : I changed this method but I got a crash again when deleting 更新 :我更改了此方法,但是删除时再次崩溃
"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
}
Update 1 : I entered these characters in the textView 更新1 :我在textView中输入了这些字符
( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎° ༽つ
Then I started to delete the characters with the right to the left after the three right few symbols were deleted ° ༽つ
, and the 🏎 car emoji has left, then I can not get the range, since I put the guard and application doesn't crash, if I remove that of course there will be app crash. 然后在删除了三个右三个符号
° ༽つ
after之后,我开始删除左侧右边的字符,并且🏎car emoji表情已经离开,然后我无法得到范围,因为我放了防护罩,而应用程序没有崩溃,如果我删除它,那么肯定会发生应用崩溃。
Full code 完整代码
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
}
}
Update 2 : After talking with Martin, I found and provided one detail that this problem only happens with the Google keyboard, and with the default keyboard everything works as expected. 更新2 :与Martin交谈后,我发现并提供了一个细节,该问题仅在Google键盘上发生,并且在默认键盘下,一切正常。
The original line I had was "( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎° ༽つ”
, this line is used for an example.If I start deleting this line from left to right, I get the app crash, Martin asked to show the latest data in the console before the app crashes, last print before crash is textView" "( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎" "range" {27, 1}
我原来的行是
"( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎° ༽つ”
,以该行为例。如果我开始从左到右删除该行,应用程序崩溃时,马丁要求在应用程序崩溃前在控制台中显示最新数据,崩溃前的最后打印为textView" "( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎" "range" {27, 1}
As it turned out in the discussion: 在讨论中发现:
the text view delegate method is called with 使用以下命令调用文本视图委托方法
textView.text = "( ͡° ͜ʖ ͡🇺🇸°)༼ つ ͡° ͜ʖ ͡🏎" range = { 27, 1 }
and then 接着
let newRange = Range(range, in: textView.text)
returns nil
. 返回
nil
。
The reason is that the range points into the “middle” of the 🏎
character, which is stored as a UTF-16 surrogate pair. 原因是范围指向
🏎
字符的“中间”,该字符存储为UTF-16代理对。 Here is a simplified self-contained example: 这是一个简化的独立示例:
let text = "Hello 🏎!"
let range = NSRange(location: 7, length: 1)
let newRange = Range(range, in: text)
print(newRange as Any) // nil 😭😭
This looks like a bug (in the Google keyboard?) to me, but there is a possible workaround. 对我来说,这看起来像是个bug(在Google键盘上?),但是有可能的解决方法。
The “trick” is to determine the closest surrounding range of “composed character sequences,” and here is how that can be done (compare From any UTF-16 offset, find the corresponding String.Index that lies on a Character boundary ): “技巧”是确定“组合字符序列”的最接近范围,这是可以做到的(比较任何UTF-16偏移量,找到位于Character边界上的相应String.Index ):
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)
}
}
Now 现在
let newRange = textView.text.safeRange(from: range)
returns a String
range that enclosed the entire 🏎
character. 返回包含整个
🏎
字符的String
范围。 In our simplified example: 在我们的简化示例中:
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 🚂!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.