如何在Swift中用CTFontCopyCharacterSet()获取字体的所有字符?

How to get all characters of the font with CTFontCopyCharacterSet() in Swift?

如何获取Swift中CTFontCopyCharacterSet()字体的所有字符? ... 适用于 macOS?

根据 Swift 中的 OSX: CGGlyph to UniChar 答案实施方法时出现问题。

func createUnicodeFontMap() {
    // Get all characters of the font with CTFontCopyCharacterSet().
    let cfCharacterSet: CFCharacterSet = CTFontCopyCharacterSet(ctFont)

    //    
    let cfCharacterSetStr = "\(cfCharacterSet)"
    print("CFCharacterSet: \(cfCharacterSet)")  

    // Map all Unicode characters to corresponding glyphs
    var unichars = [UniChar](…NYI…) // NYI: lacking unichars for CFCharacterSet
    var glyphs = [CGGlyph](repeating: 0, count: unichars.count)
    guard CTFontGetGlyphsForCharacters(
        ctFont, // font: CTFont
        &unichars, // characters: UnsafePointer<UniChar>
        &glyphs, // UnsafeMutablePointer<CGGlyph>
        unichars.count // count: CFIndex
        )
        else {
            return
    }

    // For each Unicode character and its glyph, 
    // store the mapping glyph -> Unicode in a dictionary.
    // ... NYI
}

如何使用 CFCharacterSet 检索实际字符一直难以捉摸。 cfCharacterSet 实例提供的自动完成显示没有相关方法。

并且 Core Foundation > CFCharacterSet 似乎有创建另一个 CFCharacterSet 的方法,但没有提供 array|list|string of unichars 来创建映射字典的方法。


注意:我正在寻找一种不特定于 iOS 的解决方案,如 中使用 UIFont.

你可以这样做。

let cs = CTFontCopyCharacterSet(font) as NSCharacterSet
let bitmapRepresentation = cs.bitmapRepresentation

位图的格式在 CFCharacterSetCreateWithBitmapRepresentation

的参考页中定义

CFCharacterSet toll-free 桥接到 Cocoa 基金会对应 NSCharacterSet,并且可以桥接到相应的 Swift 值类型 CharacterSet:

let charset = CTFontCopyCharacterSet(ctFont) as CharacterSet

然后NSArray from NSCharacterSet中的方法可用于枚举该字符集的所有Unicode标量值(包括non-BMP点,即大于U+FFFF的Unicode标量值)。

CTFontGetGlyphsForCharacters() 需要 non-BMP 个字符作为代理项对,即作为 UTF-16 代码单元数组。

把它放在一起,函数看起来像这样:

func createUnicodeFontMap(ctFont: CTFont) ->  [CGGlyph : UnicodeScalar] {

    let charset = CTFontCopyCharacterSet(ctFont) as CharacterSet

    var glyphToUnicode = [CGGlyph : UnicodeScalar]() // Start with empty map.

    // Enumerate all Unicode scalar values from the character set:
    for plane: UInt8 in 0...16 where charset.hasMember(inPlane: plane) {
        for unicode in UTF32Char(plane) << 16 ..< UTF32Char(plane + 1) << 16 {
            if let uniChar = UnicodeScalar(unicode), charset.contains(uniChar) {

                // Get glyph for this `uniChar` ...
                let utf16 = Array(uniChar.utf16)
                var glyphs = [CGGlyph](repeating: 0, count: utf16.count)
                if CTFontGetGlyphsForCharacters(ctFont, utf16, &glyphs, utf16.count) {
                    // ... and add it to the map.
                    glyphToUnicode[glyphs[0]] = uniChar
                }
            }
        }
    }

    return glyphToUnicode
}