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

Val*_*rov 3 unicode swift swift2

我发现函数String.characters.count的一个奇怪的行为,其中行是表情符号标志:

import UIKit

var flag = ""
print(flag.characters.count)
print(flag.unicodeScalars.count)
print(flag.utf16.count)
print(flag.utf8.count)
flag = "000"
print(flag.characters.count)
print(flag.unicodeScalars.count)
print(flag.utf16.count)
print(flag.utf8.count)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我想在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
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 5

Swift 4更新(Xcode 9)

截至Swift 4(使用Xcode 9 beta测试)标记(即区域指示符对)被视为单个字形集群,符合Unicode 9标准.因此,计算标志并删除最后一个字符(不管它是否是标志)现在简单如下:

var flags = ""
print(flags.count) // 6

flags.removeLast()
print(flags.count) // 5
print(flags) // 
Run Code Online (Sandbox Code Playgroud)

(Swift 3及更早版本的旧答案:)

没有错误.一系列"区域指标"字符是单个"扩展字形集群",这就是原因

var flag = ""
print(flag.characters.count)
Run Code Online (Sandbox Code Playgroud)

print 1(比较Swift countElements()在count flag表情符号时返回不正确的值).

另一方面,上面的字符串由12个Unicode标量(是+)组成,每个标量都需要两个UTF-16代码点.

要将字符串分成"可见实体",您必须考虑"组合字符序列",比较如何知道两个表情符号是否将显示为一个表情符号?.

我没有一个优雅的解决方案(也许有人有更好的解决方案).但是一种选择是将字符串分成组合字符数组,必要时从数组中删除元素,然后再次组合字符串.

例:

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) // 
Run Code Online (Sandbox Code Playgroud)