首页 > 解决方案 > Python Unicode - 可以在 Windows 控制台中打印哪些字符?

问题描述

Python 可以在 Windows 控制台中打印哪些 Unicode 字符?

以下代码

for code in range(1114112):
    print(chr(code), end=",")

给出了不起眼的结果,包括一个错误:

UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 0: surrogates not allowed

str然而,声明值最高的文档0x110000是允许的。

有没有办法让更多的字符显示?

标签: pythonwindowsunicodesurrogate-pairs

解决方案


要回答您的问题,我们需要检查几层 Unicode。

有效的 Unicode 代码点是从 0 到 U+10FFFF。您可能会发现unicodedata.category(char)哪个类别具有 Unicode 代码点。

从 U+D800 到 U+DFFF 的值是代理项,不应使用它们(并且它们不能在 UTF-16 中编码/解码)。[它们用于将 UCS-2(如此古老的 Unicode,直到 U+FFFF 的代码点)增强到 UTF-16(到 U+10FFFF)。旧程序/语言(如 Javascript)可能使用两个代理表示,而不是一个 UTF-16 代码点]。

注意:Python 允许它们是因为surrogateescape(主要用于读取 sys.argv),但您应该忽略它们,但只能在内部使用它们,然后才能正确转换它们。

因此,请勿尝试使用此类代码。

还有非字符:U+FDD0–U+FDEF,以及 FFFE 或 FFFF(即 U+FFFE、U+FFFF、U+1FFFE、U+1FFFF、... U+10FFFE、U+10FFFF)[来自维基百科, Unicode ],不应该使用,但是 ev。BOM (U+FEFF),但在这种情况下仅作为第一个字符。原因:第一块:非字符 U+FDD0 到 U+FDEF 的目的是什么?,其他:自动检测编码,所以我们不应该有混淆的代码点:如果你检测到它们,你知道你使用了错误的编码,你改变了编码,直到你得到一个有效的第一个代码点。

现在,使用unicodedata.category(char),您还可以获得代码的类别(请参阅Unicode 字符类别)。直到 U+1F 和 U+7F–U+9F 的字符都是控制字符,不要打印它们。

您可能有格式化字符,这可能会修改附近的字符。

因此,您可能希望排除C*(注意:这将丢弃所有上述字符)以及Z*(空格)字符类别。

所以你有unicodedata标准模块已知的可打印字符。用于unicodedata.unidata_version检查数据库更新的 unicode 版本。你可能会。允许Cn类别(未分配):也许现在它们已分配。

但这还不够。您需要一种字体来显示这些字符。谷歌有“No Tofu fonts”,这是(我认为)最完整的字体。

但这还不够。你只得到字符的标准表示(可能不会,你应该在每个字符之后添加一个 U+200C (ZWNJ),以强制字体不加入字符(例如在印度语言中)。但是你错过了所有的字符它们由代码点的组合表示:例如,许多重音字符、用圆圈或正方形包围的字符、国家标志(您需要按正确顺序排列的两个国家代码字符)等。

注意:我很好奇如何从字体文件中获取所有字形,但这不是你的问题。

附录:

我忘了说:组合字符不能单独显示,所以你需要在eg前面加上U+25CC,你可以检查它们unicodedata.combining(chr)

所以你可以使用这个代码

# if your console is not UTF-8 (or any unicode encoding) and python
# do no get it, you will get garbage
import unicodedata

combining = '\u25cc'
placeholder = '\ufffd'
zwnj = '\u200c'

line = ''
for code in range(0x10FFFF+1):
    c = chr(code)
    cat = unicodedata.category(c)
    if cat.startswith('C'):  # and cat != 'Cn':
        r = placeholder
    elif cat.startswith('Z'):
        r = ' '
    elif unicodedata.combining(c) > 0:
        r = combining + c + zwnj
    else:
        r = c + zwnj
    line += r
    if code % 256 == 255:
        print(line)
        line = ''

推荐阅读