Ответ 1
Есть ли константа Python для пробелов Unicode?
Краткий ответ: Нет. Я лично использовал эти символы (в частности, числовые кодовые точки) в базе кода Python, и такой константы там нет.
В следующих разделах объясняется, почему это не нужно, и как это реализовано, если эта информация не доступна как константа. Но иметь такую константу тоже было бы очень плохой идеей.
Если Консорциум Unicode добавил еще один символ/кодовую точку, которая является семантически пробелом, у сопровождающих Python будет плохой выбор между продолжением поддержки семантически неверного кода или изменением константы и, возможно, нарушением ранее существующего кода, который может (нежелательно) делать предположения о постоянной не меняется.
Как он мог добавить эти символьные кодовые точки? В Unicode есть 1111998 возможных символов. Но только 120 672 заняты по версии 8. Каждая новая версия Unicode может добавлять дополнительные символы. Один из этих новых символов может быть формой пробела.
Информация хранится в динамически генерируемой функции C
Код, который определяет, что является пробелом в Юникоде, является следующим динамически генерируемым кодом.
# 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 мы не сможем изменить константы по причинам обратной совместимости.
Сгенерированный код
Здесь сгенерированный код в настоящее время на кончике:
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;
}
Делая свою собственную константу:
Следующий код (из моего ответа здесь) в Python 3 генерирует константу всех пробелов:
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 (в 2.7 случается так, что вся строка выше также распознается как пробел), а в Python 3 он игнорируется, так как строковые литералы по умолчанию являются юникодом.