当字符串中包含非ASCII字符时,如何将C字符串(char数组)转换为Python字符串?

发布于 2021-01-29 16:48:01

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

Python字符串通常应为类型unicode-例如,0x93在Windows-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;
}
关注者
0
被浏览
262
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    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的“ decode”方法。就像是:

    #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方法没有做同样的事情,所以我不确定这是否仍然有用。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看