如何确定Swift String的显示计数?

时间:2019-06-19 22:08:24

标签: swift string emoji-tones

我已经审查了诸如Get the length of a StringWhy are emoji characters like ?‍?‍?‍? treated so strangely in Swift strings?之类的问题,但都没有涵盖这个特定问题。

当尝试将肤色修改器应用于表情符号字符时,一切都开始了(请参阅Add skin tone modifier to an emoji programmatically)。这导致您想知道将肤色修饰符应用于常规字符(例如"A")会发生什么情况。

示例:

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

我正在尝试检测第二种情况。这两个字符串的count均为1。两个字符串的unicodeScalars.count均为2。

如何确定显示的结果字符串是否显示为单个字符?换句话说,我如何确定是否已将肤色修改器应用于制作单个角色?

我尝试了几种方法来转储有关字符串的信息,但是没有一种方法可以提供期望的结果。

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("??")

2 个答案:

答案 0 :(得分:2)

如果在不支持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

答案 1 :(得分:0)

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

例如:

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标量,但是一个是count 1,另一个是count2。当然,这是一个有用的区别。