To get the UTF8-encoded byte count of a string, I would simply do the following.
let str = "it's 🌮 time"
let totalUTF8EncodedBytes = str.utf8.count
print(totalUTF8EncodedBytes) // 14
However, if I’m given an NSRange of this string, how can I get the UTF8-encoded byte count of that range?
To add some context, I want to limit the characters entered into a text view both with a character limit and a byte limit. The character limit is done. The byte limit also technically works but when pasting a block of text that should fit within the byte limit over an existing range of text, it returns false when it should return true since it doesn’t account for the range.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let charLimit = characterLimit {
let currentChars = textView.text.count
let newChars = text.count - range.length
let totalChars = currentChars + newChars
return totalChars <= charLimit
}
if let byteLimit = utf8EncodedByteLimit {
let currentBytes = textView.text.utf8.count
let newBytes = text.utf8.count
let totalBytes = currentBytes + newBytes
return totalBytes <= byteLimit
}
return false
}
>Solution :
All you need to do is get the substring from the range:
let subStr = (str as NSString).substring(with: range)
Then you can get the utf8.count of subStr, or do it all on one line:
let subCount = (str as NSString).substring(with: range).utf8.count
But for your shouldChangeTextIn, you can simply do the following:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newStr = (textView.text! as NSString).replacingCharacters(in: range, with: text)
if let charLimit = characterLimit {
return newStr.count <= charLimit
}
if let byteLimit = utf8EncodedByteLimit {
return newStr.utf8.count <= byteLimit
}
return false
}