Unicode 空格有 Python 常量吗?

Is there a Python constant for Unicode whitespace?

string 模块包含一个 whitespace 属性,它是由所有被视为空白的 ASCII 字符组成的字符串。是否有相应的常量也包含 Unicode 空格,例如 no-break space (U+00A0)? We can see from the question "strip() and strip(string.whitespace) give different results" 至少 strip 知道额外的 Unicode 空白字符。

此问题被识别为 的重复问题 在 Python 中,如何列出由 POSIX 扩展正则表达式 [:space:]? 匹配的所有字符,但该问题的答案确定了 搜索 用于空白字符以生成您自己的列表。这是一个耗时的过程。我的问题具体是关于 constant.

Is there a Python constant for Unicode whitespace?

简答:没有。我亲自在Python代码库中查找这些字符(具体来说,数字代码点),这样的常数是没有。

以下部分解释了为什么它不是必需的,以及如何在没有此信息作为常量可用的情况下实现它。但是拥有这样一个常量也是一个非常糟糕的主意。

如果 Unicode 联盟添加另一个 character/code-point 语义空白,Python 的维护者将在继续支持语义不正确的代码或更改常量并可能破坏预定义之间做出糟糕的选择现有代码可能(不明智地)假设常量不变。

如何添加这些字符代码点? Unicode 中有 1,111,998 个可能的字符。但截至 version 8 只有 120,672 个被占用。每个新版本的 Unicode 都可能添加额外的字符。其中一个新字符可能是一种空白字符。

信息存储在动态生成的 C 函数中

决定unicode中什么是空白的代码是下面动态生成的code

# Generate code for _PyUnicode_IsWhitespace()
print("/* Returns 1 for Unicode characters having the bidirectional", file=fp)
print(" * type 'WS', 'B' or 'S' or the category 'Zs', 0 otherwise.", file=fp)
print(" */", file=fp)
print('int _PyUnicode_IsWhitespace(const Py_UCS4 ch)', file=fp)
print('{', file=fp)
print('    switch (ch) {', file=fp)
for codepoint in sorted(spaces):
    print('    case 0x%04X:' % (codepoint,), file=fp)
print('        return 1;', file=fp)
print('    }', file=fp)
print('    return 0;', file=fp)
print('}', file=fp)
print(file=fp)

这是一个 switch 语句,它是一个常量代码块,但此信息不能像字符串模块那样作为模块“常量”使用。它隐藏在从 C 编译的函数中,不能直接从 Python.

访问

这可能是因为随着越来越多的代码点被添加到 Unicode,出于向后兼容的原因,我们将无法更改常量。

生成的代码

这是当前生成的代码at the tip:

int _PyUnicode_IsWhitespace(const Py_UCS4 ch)
{
    switch (ch) {
    case 0x0009:
    case 0x000A:
    case 0x000B:
    case 0x000C:
    case 0x000D:
    case 0x001C:
    case 0x001D:
    case 0x001E:
    case 0x001F:
    case 0x0020:
    case 0x0085:
    case 0x00A0:
    case 0x1680:
    case 0x2000:
    case 0x2001:
    case 0x2002:
    case 0x2003:
    case 0x2004:
    case 0x2005:
    case 0x2006:
    case 0x2007:
    case 0x2008:
    case 0x2009:
    case 0x200A:
    case 0x2028:
    case 0x2029:
    case 0x202F:
    case 0x205F:
    case 0x3000:
        return 1;
    }
    return 0;
}

创建自己的常量:

下面的代码(来自我的回答here),在Python3中,生成一个所有空格的常量:

import re
import sys

s = ''.join(chr(c) for c in range(sys.maxunicode+1))
ws = ''.join(re.findall(r'\s', s))

作为一种优化,您可以将它存储在代码库中,而不是在每个新进程中自动生成它,但我会警告不要假设它永远不会改变。

>>> ws
'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f \x85\xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000'

(链接问题的其他答案显示了如何获得 Python 2。)

请记住,在某一时刻,有些人可能认为 256 字符编码就是我们所需要的。

>>> import string
>>> string.whitespace
' \t\n\r\x0b\x0c'

如果您坚持要在代码库中保留常量,只需为您的 Python 版本生成常量,并将其存储为文字:

unicode_whitespace = u'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f \x85\xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000'

u 前缀使其在 Python 2 中成为 unicode(2.7 恰好也将上面的整个字符串识别为空格),而在 Python 3 中它被忽略为字符串文字默认是unicode。