Можно ли использовать широкие символы в объектах расширения Python? - PullRequest
2 голосов
/ 01 июня 2011

Создать элемент для объекта в расширении Python C просто с базовым типом char *, используя определение T_STRING в объявлении PyMemberDef.

Почему не существует эквивалента для wchar_t *? А если на самом деле есть один, что это?

, например

struct object содержит char *text

PyMemberDef массив имеет {"text", T_STRING, offsetof(struct object, text), READONLY, "This is a normal character string."}

против чего-то вроде

struct object содержит wchar_t *wtext

PyMemberDef массив имеет {"wtext", T_WSTRING, offsetof(struct object, wtext), READONLY, "This is a wide character string"}

Я понимаю, что что-то вроде PyUnicode_AsString() и связанные с ним методы можно использовать для кодирования данных в UTF-8, сохранения их в базовой строке символов и последующего декодирования, но для этого потребуется обертка универсального * Методы / функции 1030 * и setattr с теми, которые учитывают закодированный текст, и это не очень полезно, когда вам нужны массивы символов фиксированного размера элемента в структуре и не хотите эффективное количество символов, которые могут быть сохранены в это меняться.

1 Ответ

2 голосов
/ 01 июня 2011

Использование wchar_t напрямую не является переносимым. Вместо этого Python определяет Py_UNICODE тип в качестве единицы хранения для символа Unicode.

В зависимости от платформы, Py_UNICODE может быть определено как wchar_t, если доступно, или беззнаковое короткое / целое / длинное, ширина которого будет варьироваться в зависимости от конфигурации Python (UCS2 против UCS4) и архитектуры и компилятор C используется. Вы можете найти соответствующие определения в unicodeobject.h.

Для вашего случая использования ваш объект может иметь атрибут, представляющий собой строку Unicode, используя T_OBJECT:

static struct PyMemberDef attr_members[] = {
  { "wtext", T_OBJECT, offsetof(PyAttrObject, wtext), READONLY, "wide string"}
  ...

Вы можете выполнить проверку типа в инициализаторе объекта:

...
if (!PyUnicode_CheckExact(arg)) {
    PyErr_Format(PyExc_ValueError, "arg must be a unicode string");
    return NULL;
}
Py_INCREF(arg);
self->wtext = arg;
...

Если вам когда-нибудь понадобится перебрать низкоуровневые символы в строке Unicode, есть макрос, который возвращает Py_UNICODE *:

int i = 0;
Py_ssize_t size = PyUnicode_GetSize(self->wtext);
Py_UNICODE *chars = PyUnicode_AS_UNICODE(self->wtext);
for (i = 0; i < size; i++) {
    // use chars[i]
    ...
...