我在C程序中嵌入了Python解释器。假设C程序从文件中读取一些字节到char数组,并且(以某种方式)学习字节表示具有特定编码的文本(例如,ISO 8859-1,Windows-1252或UTF-8)。如何将此char数组的内容解码为Python字符串?
Python字符串通常应为unicode
类型 - 例如,Windows-1252编码输入中的0x93
变为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 :(得分: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“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以这种方式工作的原因是什么。 very old thread on python-dev似乎表明它与链接输出有关,但由于Python方法没有这样做,我不确定它是否仍然相关。
答案 1 :(得分:3)
您不希望将字符串解码为Unicode表示形式,您只想将其视为字节数组,对吗?
只需使用PyString_FromString
:
char *cstring;
PyObject *pystring = PyString_FromString(cstring);
这就是全部。现在你有了一个Python str()
对象。请参阅此处的文档:https://docs.python.org/2/c-api/string.html
我对如何指定“str”或“unicode”感到有点困惑。如果您有非ASCII字符,它们会完全不同。如果你想解码一个C字符串和你确切知道它所在的字符集,那么是的,PyString_DecodeString
是一个很好的起点。
答案 2 :(得分:2)
尝试在“if (!py_string)
”子句中调用PyErr_Print()
。也许python异常会给你更多的信息。