Come convertire una stringa C (array di caratteri) in una stringa Python quando nella stringa sono presenti caratteri non ASCII?

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

Domanda

Ho incorporato un interprete Python in un programma C. Supponiamo che il programma C legga alcuni byte da un file in un array di caratteri e apprenda (in qualche modo) che i byte rappresentano il testo con una certa codifica (ad es. ISO 8859-1, Windows-1252 o UTF-8). Come posso decodificare il contenuto di questo array di caratteri in una stringa Python?

La stringa Python dovrebbe in generale essere di tipo unicode & # 8212; ad esempio, un 0x93 nell'input codificato di Windows-1252 diventa un u '\ u0201c '.

Ho provato a usare PyString_Decode , ma fallisce sempre quando ci sono caratteri non ASCII nella stringa. Ecco un esempio che fallisce:

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

Il messaggio di errore è UnicodeEncodeError: il codec 'ascii' non può codificare il carattere u '\ u201c' nella posizione 0: ordinale non compreso nell'intervallo (128) , che indica che ascii viene utilizzata anche se nella chiamata a PyString_Decode viene specificato windows_1252 .

Il codice seguente risolve il problema usando PyString_FromString per creare una stringa Python dei byte non codificati, quindi chiamando il suo metodo 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;
}
È stato utile?

Soluzione

PyString_Decode fa questo:

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, fa sostanzialmente quello che stai facendo nel tuo secondo esempio: converte in una stringa, quindi decodifica la stringa. Il problema qui sorge da PyString_AsDecodedString, piuttosto che da PyString_AsDecodedObject. PyString_AsDecodedString esegue PyString_AsDecodedObject, ma tenta quindi di convertire l'oggetto unicode risultante in un oggetto stringa con la codifica predefinita (per te, sembra ASCII). Ecco dove fallisce.

Credo che dovrai fare due chiamate, ma puoi usare PyString_AsDecodedObject piuttosto che chiamare il pitone "decodifica". metodo. Qualcosa del tipo:

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

Non sono del tutto sicuro di quale sia il ragionamento alla base di PyString_Decode in questo modo. Un thread molto vecchio su python-dev sembra indica che ha qualcosa a che fare con il concatenamento dell'output, ma poiché i metodi Python non fanno lo stesso, non sono sicuro che sia ancora pertinente.

Altri suggerimenti

Non vuoi decodificare la stringa in una rappresentazione Unicode, vuoi solo trattarla come una matrice di byte, giusto?

Basta usare PyString_FromString :

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

Questo è tutto. Ora hai un oggetto Python str () . Consulta i documenti qui: https://docs.python.org/2/c- API / string.html

Sono un po 'confuso su come specificare " str " o " unicode. " Sono abbastanza diversi se hai caratteri non ASCII. Se vuoi decodificare una stringa C e sai esattamente in quale set di caratteri si trova, quindi sì, PyString_DecodeString è un buon punto di partenza.

Prova a chiamare PyErr_Print () in il " if (! py_string) " clausola. Forse l'eccezione di Python ti darà qualche informazione in più.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top