如何确定Swift字符串的显示次数?

How to determine the display count of a Swift String?

我已经复习过诸如 Get the length of a String and 之类的问题,但都没有涵盖这个具体问题。

这一切都始于尝试将肤色修饰符应用于表情符号字符(参见 )。这导致想知道当您将肤色修饰符应用于 "A".

等常规字符时会发生什么

示例:

let tonedThumbsUp = "" + "" // 
let tonedA = "A" + "" // A

我正在尝试检测第二个案例。这两个字符串的 count 都是 1。unicodeScalars.count 都是 2。

如何确定结果字符串在显示时是否显示为单个字符?换句话说,如何判断皮肤色调修改器是否应用于单个角色?

我已经尝试了几种方法来转储有关字符串的信息,但 none 给出了所需的结果。

func dumpString(_ str: String) {
    print("Raw:", str, str.count)
    print("Scalars:", str.unicodeScalars, str.unicodeScalars.count)
    print("UTF16:", str.utf16, str.utf16.count)
    print("UTF8:", str.utf8, str.utf16.count)
    print("Range:", str.startIndex, str.endIndex)
    print("First/Last:", str.first == str.last, str.first, str.last)
}

dumpString("A")
dumpString("\u{1f469}\u{1f3fe}")

结果:

Raw: A 1
Scalars: A 2
UTF16: A 3
UTF8: A 3
First/Last: true Optional("A") Optional("A")
Raw:  1
Scalars:  2
UTF16:  4
UTF8:  4
First/Last: true Optional("") Optional("")

如果您在不支持 Fitzpatrick 修饰符的系统上打印会怎样?无论系统使用什么未知字符占位符,您都会跟在后面。

所以我认为要回答这个问题,您必须咨询您系统的排字员。对于 Apple 平台,您可以使用 Core Text 创建一个 CTLine 然后计算该行的字形运行数。示例:

import Foundation
import CoreText

func test(_ string: String) {
    let richText = NSAttributedString(string: string)
    let line = CTLineCreateWithAttributedString(richText as CFAttributedString)
    let runs = CTLineGetGlyphRuns(line) as! [CTRun]
    print(string, runs.count)
}

test("" + "")
test("A" + "")
test("B\u{0300}\u{0301}\u{0302}" + "")

macOS 10.14.6 Beta (18G48f) 上 Xcode 10.2.1 中 macOS 操场的输出:

 1
A 2
B̀́̂ 2

我认为可以通过查看修饰符是否存在以及如果存在是否增加了字符数来对此进行推理。

例如:

let tonedThumbsUp = "" + ""
let tonedA = "A" + ""
tonedThumbsUp.count // 1
tonedThumbsUp.unicodeScalars.count // 2
tonedA.count //2
tonedThumbsUp.unicodeScalars.count //2
let c = "\u{1F3FB}"
tonedThumbsUp.contains(c) // true
tonedA.contains(c) // true

好的,所以它们都包含一个修饰符,它们都包含两个 unicode 标量,但一个是计数 1,另一个是计数 2。这当然是一个有用的区别。