문자열에 비 ASCII 문자가있을 때 C 문자열 (char 배열)을 Python 문자열로 변환하는 방법은 무엇입니까?
-
03-07-2019 - |
문제
C 프로그램에 Python 통역사를 포함 시켰습니다. C 프로그램이 파일에서 일부 바이트를 숯 배열로 읽고 바이트가 특정 인코딩 (예 : ISO 8859-1, Windows-1252 또는 UTF-8)이있는 텍스트를 나타냅니다. 이 char 어레이의 내용을 파이썬 문자열로 어떻게 디코딩합니까?
파이썬 문자열은 일반적으로 유형이어야합니다 unicode
- 예를 들어, a 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
명확하지 않은 바이트의 파이썬 문자열을 만들려면 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;
}
해결책
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_asdecodedobject보다는 pystring_asdecodedstring에서 발생합니다. pystring_asdecodedstring pystring_asdecodedobject를 수행하지만 결과 유니 코드 객체를 기본 인코딩을 사용하여 문자열 객체로 변환하려고합니다 (ASCII처럼 보입니다). 그것이 실패하는 곳입니다.
두 번의 호출을해야한다고 생각하지만 Python "Decode"메소드를 호출하지 않고 pystring_asdecodedobject를 사용할 수 있습니다. 같은 것 :
#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의 아주 오래된 실 출력을 체인하는 것과 관련이 있음을 나타내는 것처럼 보이지만 파이썬 방법이 동일하지 않기 때문에 여전히 관련이 있는지 확실하지 않습니다.
다른 팁
문자열을 유니 코드 표현으로 디코딩하고 싶지 않습니다. 바이트 배열로 취급하고 싶습니까?
그냥 사용하십시오 PyString_FromString
:
char *cstring;
PyObject *pystring = PyString_FromString(cstring);
그게 다야. 이제 파이썬이 있습니다 str()
물체. 여기서 문서를 참조하십시오. https://docs.python.org/2/c-api/string.html
나는 "str"또는 "unicode"를 지정하는 방법에 대해 약간 혼란스러워합니다. ASCII가 아닌 문자가 있으면 상당히 다릅니다. C 문자열을 디코딩하려는 경우 그리고 당신은 어떤 캐릭터를 설정하는지 정확히 알고 있습니다. 그렇습니다. PyString_DecodeString
시작하기에 좋은 곳입니다.
전화 해보세요 PyErr_Print()
""에서 "if (!py_string)
"조항. 아마도 Python 예외는 더 많은 정보를 제공 할 것입니다.