Wie ein C-String (char-Array) in einen Python-String konvertieren, wenn Nicht-ASCII-Zeichen in der Zeichenfolge sind?

StackOverflow https://stackoverflow.com/questions/213628

Frage

Ich habe ein Python-Interpreter in einem C-Programm eingebettet. Angenommen, das C-Programm liest einige Bytes aus einer Datei in ein char Array und lernt (irgendwie), dass der Bytes repräsentiert Text mit einer bestimmten Codierung (beispielsweise ISO 8859-1, von Windows-1252 oder UTF-8). Wie entschlüsseln wir den Inhalt dieses char-Array in einen Python-String?

Der Python-String sollte im Allgemeinen als Typ unicode-zum Beispiel ein 0x93 in Windows-1252 codierte Eingang wird ein u'\u0201c'.

Ich habe zu verwenden PyString_Decode versucht, aber es funktioniert nicht immer, wenn es Nicht-ASCII-Zeichen in der Zeichenfolge ist. Hier ist ein Beispiel, das fehlschlägt:

#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;
}

Die Fehlermeldung ist UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128), was darauf hindeutet, dass die ascii Codierung selbst verwendet wird, obwohl wir windows_1252 im Aufruf angeben PyString_Decode.

Der folgende Code funktioniert, um das Problem durch PyString_FromString mit einem Python-String des undekodierten Bytes zu erstellen, dann seine decode Methode aufrufen:

#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;
}
War es hilfreich?

Lösung

PyString_Decode tut dies:

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, es ist im Grunde, was Sie in Ihrem zweiten Beispiel tun - konvertiert in einen String, dann die Zeichenfolge entschlüsseln. Das Problem hierbei ergibt sich aus PyString_AsDecodedString, anstatt PyString_AsDecodedObject. PyString_AsDecodedString tut PyString_AsDecodedObject, aber dann versucht, das resultierende Unicode-Objekt in ein String-Objekt mit der Standard-Kodierung zu konvertieren (für Dich sieht aus wie das ASCII ist). Das ist, wo es funktioniert nicht.

Ich glaube, Sie werden zwei Anrufe tun müssen - aber Sie können PyString_AsDecodedObject verwenden, anstatt die Python „decode“ Methode aufrufen. So etwas wie:

#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;
}

Ich bin mir nicht ganz sicher, was die Argumentation hinter PyString_Decode auf diese Weise funktioniert. Ein sehr alten Thread auf Python-dev scheint zeigen, dass es etwas mit Chaining des Ausgangs zu tun hat, aber da die Python Methoden das gleiche nicht tun, ich bin nicht sicher, ob das immer noch relevant ist.

Andere Tipps

Sie wollen nicht die Zeichenfolge in eine Unicode-Darstellung entschlüsseln, mögen Sie einfach es zu behandeln, als ein Array von Bytes, nicht wahr?

Just PyString_FromString verwenden:

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

Das ist alles. Jetzt haben Sie eine Python str() Objekt. Siehe docs hier: https://docs.python.org/2/c- api / string.html

Ich bin ein wenig verwirrt darüber, wie „str“ oder angeben „Unicode“. Sie sind ganz anders, wenn Sie nicht-ASCII-Zeichen haben. Wenn Sie ein C-Zeichenfolge entschlüsseln wollen und Sie genau wissen, was Zeichensatz es ist in, dann ja, PyString_DecodeString ist ein guter Ort zu starten.

Versuchen Sie PyErr_Print() in der "if (!py_string)" Klausel aufrufen. Vielleicht ist die Python-Ausnahme wird Ihnen einige weitere Informationen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top