swift2 如何删除字符串末尾的标志?

lzfw57am  于 2022-11-06  发布在  Swift
关注(0)|答案(2)|浏览(234)

我发现函数String.characters.count在有Emoji标志的行中有一个奇怪的行为:

import UIKit

var flag = "🇨🇦🇨🇦🇨🇦🇨🇦🇨🇦🇨🇦"
print(flag.characters.count)
print(flag.unicodeScalars.count)
print(flag.utf16.count)
print(flag.utf8.count)
flag = "🇨🇦0🇨🇦0🇨🇦0"
print(flag.characters.count)
print(flag.unicodeScalars.count)
print(flag.utf16.count)
print(flag.utf8.count)

我想在UITextView中编写和编辑时限制文本的字符串长度。实际上我的代码是这样的:

var lastRange: NSRange? = nil
var lastText: String? = nil

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText string: String) -> Bool {
    if string == "\n" {
        // Execute same code
        return false
    } 
    var text = string.uppercaseString
    if lastText != text || lastRange != nil && (lastRange!.location != range.location || lastRange!.length != range.length) {
        lastRange = range
        lastText = text

        var text = (self.textView.text ?? "" as NSString).stringByReplacingCharactersInRange(range, withString: string)

        // Delete chars if length more kMaxLengthText 
        while text.utf16.count >= kMaxLengthText {
            text.removeAtIndex(text.endIndex.advancedBy(-1))
        }
        // Set position after insert text
        self.textView.selectedRange = NSRange(location: range.location + lastText!.utf16.count, length: 0)
    }
    return false
}
wwwo4jvm

wwwo4jvm1#

针对Swift 4(Xcode 9)的更新

从Swift 4开始(用Xcode 9测试),标志(即成对的区域指示符)被视为一个单一的字形簇,这是Unicode 9标准所要求的。因此,计数标志并删除最后一个字符(无论它是不是标志)现在就像这样简单:

var flags = "🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦🇨🇦"
print(flags.count) // 6

flags.removeLast()
print(flags.count) // 5
print(flags) // 🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦
  • (Swift 3及更早版本的旧答案:)*

没有bug。一个“区域指示符”字符序列是一个单一的“扩展字素簇”,这就是为什么

var flag = "🇨🇦🇨🇦🇨🇦🇨🇦🇨🇦🇨🇦"
print(flag.characters.count)

打印1(比较Swift countElements() return incorrect value when count flag emoji)。
另一方面,上面的字符串由12个Unicode标量(🇨🇦is🇨+🇦)组成,每个标量都需要两个UTF-16码位。
要将字符串分离成“可见实体”,您必须考虑“组合字符序列”,请比较How to know if two emojis will be displayed as one emoji?
我没有一个优雅的解决方案(也许有人有更好的解决方案),但有一个选择是将字符串分成一个由字符组成的数组,如果需要,从数组中删除元素,然后再次合并字符串。
示例:

extension String {

    func composedCharacters() -> [String] {
        var result: [String] = []
        enumerateSubstringsInRange(characters.indices, options: .ByComposedCharacterSequences) {
            (subString, _, _, _) in
            if let s = subString { result.append(s) }
        }
        return result
    }
}

var flags = "🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦🇨🇦"
var chars = flags.composedCharacters()
print(chars.count) // 6
chars.removeLast()
flags = chars.joinWithSeparator("")
print(flags) // 🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦
thtygnil

thtygnil2#

@马丁对swift 3的回答,有一些修改
注意:我已将扩展转换为函数

func composedCharacters(str:String) -> [String] {
    var result: [String] = []
    str.enumerateSubstrings(in: str.startIndex..<str.endIndex,options: .byComposedCharacterSequences) {
        (subString, _, _, _) in
        if let s = subString { result.append(s) }
    }
    return result
}
var flags = "🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦🇨🇦"
var chars = composedCharacters(str:flags)
print(chars.count) // 6
chars.removeLast()
flags = chars.joined(separator:"")
print(flags) // 🇩🇪🇩🇪🇩🇪🇨🇦🇨🇦

相关问题