7

我在 C 程序中嵌入了一个 Python 解释器。假设 C 程序从一个文件中读取一些字节到一个 char 数组中,并且(不知何故)得知这些字节表示具有某种编码(例如,ISO 8859-1、Windows-1252 或 UTF-8)的文本。如何将此 char 数组的内容解码为 Python 字符串?

Python 字符串通常应该是类型unicode——例如,0x93Windows-1252 编码输入中的 a 变成u'\u0201c'.

我尝试使用PyString_Decode,但是当字符串中有非 ASCII 字符时它总是失败。这是一个失败的例子:

#include <Python.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
     char c_string[] = { (char)0x93, 0 };
     PyObject *py_string;

     Py_Initialize();

     py_string = PyString_Decode(c_string, 1, "windows_1252", "replace");
     if (!py_string) {
          PyErr_Print();
          return 1;
     }
     return 0;
}

错误消息是UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128),这表明ascii即使我们windows_1252在对 的调用中指定了编码也被使用PyString_Decode

以下代码通过使用PyString_FromString创建未解码字节的 Python 字符串,然后调用其decode方法来解决此问题:

#include <Python.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
     char c_string[] = { (char)0x93, 0 };
     PyObject *raw, *decoded;

     Py_Initialize();

     raw = PyString_FromString(c_string);
     printf("Undecoded: ");
     PyObject_Print(raw, stdout, 0);
     printf("\n");
     decoded = PyObject_CallMethod(raw, "decode", "s", "windows_1252");
     Py_DECREF(raw);
     printf("Decoded: ");
     PyObject_Print(decoded, stdout, 0);
     printf("\n");
     return 0;
}
4

3 回答 3

6

PyString_Decode 这样做:

PyObject *PyString_Decode(const char *s,
              Py_ssize_t size,
              const char *encoding,
              const char *errors)
{
    PyObject *v, *str;

    str = PyString_FromStringAndSize(s, size);
    if (str == NULL)
    return NULL;
    v = PyString_AsDecodedString(str, encoding, errors);
    Py_DECREF(str);
    return v;
}

IOW,它基本上完成了您在第二个示例中所做的事情 - 转换为字符串,然后解码字符串。这里的问题来自 PyString_AsDecodedString,而不是 PyString_AsDecodedObject。PyString_AsDecodedString 执行 PyString_AsDecodedObject,但随后尝试将生成的 unicode 对象转换为具有默认编码的字符串对象(对您而言,看起来像是 ASCII)。那就是它失败的地方。

我相信您需要进行两次调用 - 但您可以使用 PyString_AsDecodedObject 而不是调用 python“解码”方法。就像是:

#include <Python.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
     char c_string[] = { (char)0x93, 0 };
     PyObject *py_string, *py_unicode;

     Py_Initialize();

     py_string = PyString_FromStringAndSize(c_string, 1);
     if (!py_string) {
          PyErr_Print();
          return 1;
     }
     py_unicode = PyString_AsDecodedObject(py_string, "windows_1252", "replace");
     Py_DECREF(py_string);

     return 0;
}

我不完全确定 PyString_Decode 以这种方式工作的原因是什么。python-dev 上的一个非常古老的线程似乎表明它与链接输出有关,但由于 Python 方法不这样做,我不确定这是否仍然相关。

于 2008-10-18T19:59:25.153 回答
3

您不想将字符串解码为 Unicode 表示,您只想将其视为字节数组,对吗?

只需使用PyString_FromString

char *cstring;
PyObject *pystring = PyString_FromString(cstring);

就这样。现在你有了一个 Pythonstr()对象。在此处查看文档:https ://docs.python.org/2/c-api/string.html

我对如何指定“str”或“unicode”有点困惑。如果你有非 ASCII 字符,它们就完全不同了。如果您想解码 C 字符串并且您确切地知道它所在的字符集,那么是的,PyString_DecodeString这是一个很好的起点。

于 2008-10-17T20:00:47.527 回答
2

尝试调用PyErr_Print()if (!py_string)”子句。也许python异常会给你一些更多的信息。

于 2008-10-17T20:47:20.787 回答