检测当Unicode字符无法正确显示时的处理方法

7
一些Unicode字符在iOS上无法显示,但在macOS上可以正确显示。同样,iOS可以显示的一些Unicode字符在watchOS上无法显示。这是由于这些平台上安装的内置字体不同造成的。
当字符无法显示时,它会出现在一个框内,显示为一个问号,如下所示:
enter image description here 我也见过一些字符显示为外星人(不确定为什么会有区别):
enter image description here 是否有一种方法可以知道在给定一个Unicode字符字符串(如“ᄥ”)时,特定的Unicode字符将不能正确地显示?
我需要适用于iOS和watchOS的解决方案。

1
也许可以使用 CTFontGetGlyphsForCharacters(...) 函数? - MirekE
你能给我们这两个的代码点吗? - Code Different
@ZoffDino 我手头没有外星人,但是对于“?”的示例,这个字符在iOS上显示为“?”: - Jordan H
我设置了Unicode(U+1F0A1),它显示为“`A1”。在移动版Safari中,当您浏览问题时,您无法看到它。 - NSDeveloper
2个回答

5

您可以使用 CTFontGetGlyphsForCharacters()来确定字体是否具有特定代码点的字形(请注意,需要检查补充字符作为代理对):

CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica"), 12, NULL);
const UniChar code_point[] = { 0xD83C, 0xDCA1 };  // U+1F0A1
CGGlyph glyph[] = { 0, 0 };
bool has_glyph = CTFontGetGlyphsForCharacters(font, code_point, glyph, 2);

或者,在 Swift 中:
let font = CTFontCreateWithName("Helvetica", 12, nil)
var code_point: [UniChar] = [0xD83C, 0xDCA1]
var glyphs: [CGGlyph] = [0, 0]
let has_glyph = CTFontGetGlyphsForCharacters(font, &code_point, &glyph, 2)

如果你想检查系统将尝试从中加载字形的完整备用字体集,请检查CTFontCopyDefaultCascadeListForLanguages()返回的所有字体。有关备用字体列表如何创建的信息,请参阅此问题的答案

如果 has_glyph 为 false,则无法显示正确吗? - NSDeveloper
如果 has_glyph == false,它将使用Last Resort字体进行渲染,显示一个方框或问号(与原始问题中一样)。 - 一二三
非常整洁!有没有更有效的方法来确定任何字体是否可以显示给定的字形,而不必在从所提到的方法返回的所有字体上运行该代码循环?我想这对于大量字形来说非常低效。 - Jordan H
1
这基本上就是系统在尝试正常渲染文本时所做的事情,因此性能不应该太差。但你可能需要缓存CTFont对象,而CTFontGetGlyphs...可以用于一次检查整个字符串(查找glyphs[i]!=0而不是返回值)。 - 一二三

0

与已知的未定义字符 U+1FFF 进行比较:

/// - Parameter font: a UIFont
/// - Returns: true if glyph exists
func glyphAvailable(forFont font:UIFont) -> Bool {
    if let refUnicodePng = Character("\u{1fff}").png(forFont: font),
        let myPng = self.png(forFont: font) {
        return refUnicodePng != myPng
    }
    return false
}

使用 png 位图:

/// - Parameter font: a UIFont
/// - Returns: an optional png representation
func png(forFont font: UIFont) -> Data? {
    let attributes = [NSAttributedStringKey.font: font]
    let charStr = "\(self)" as NSString
    let size = charStr.size(withAttributes: attributes)

    UIGraphicsBeginImageContext(size)
    charStr.draw(at: CGPoint(x: 0,y :0), withAttributes: attributes)

    var png:Data? = nil
    if let charImage = UIGraphicsGetImageFromCurrentImageContext() {
        png = UIImagePNGRepresentation(charImage)
    }

    UIGraphicsEndImageContext()
    return png
}

这里得到了回答。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接