Como para converter uma cadeia C (matriz de char) para uma cadeia pitão quando existem caracteres não ASCII na cadeia?

votos
7

Eu ter incorporado um interpretador Python em um programa C. Suponhamos que o programa C lê alguns bytes de um ficheiro para uma matriz de char e aprende (de alguma forma) que os bytes representam texto com uma certa codificação (por exemplo, ISO 8859-1, Windows 1252, ou UTF-8). Como faço para decodificar o conteúdo desta matriz de char em uma string Python?

A seqüência de Python deve, em geral, ser do tipo unicodeinstância -por, uma 0x93no Windows-1252 entrada codificada se torna um u'\u0201c'.

Tentei usar PyString_Decode, mas sempre falha quando existem caracteres não-ASCII na corda. Aqui está um exemplo que falha:

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

A mensagem de erro é UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128), o que indica que a asciicodificação é usada mesmo que especificar windows_1252na chamada para PyString_Decode.

O código a seguir funciona em torno o problema usando PyString_FromStringpara criar uma string Python dos bytes n�o codificados, em seguida, chamando seu decodemétodo:

#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;
}
Publicado 17/10/2008 em 20:58
fonte usuário
Em outras línguas...                            


3 respostas

votos
6

PyString_Decode faz isso:

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, que faz basicamente o que você está fazendo em seu segundo exemplo - converte para uma cadeia, então decodificar a seqüência. O problema aqui surge a partir PyString_AsDecodedString, ao invés de PyString_AsDecodedObject. PyString_AsDecodedString faz PyString_AsDecodedObject, mas, em seguida, tenta converter o objeto unicode resultando em um objeto string com a codificação padrão (para você, parece que é ASCII). É aí que ele falhar.

Eu acredito que você vai precisar fazer duas chamadas - mas você pode usar PyString_AsDecodedObject ao invés de chamar o método python "decodificar". Algo como:

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

Eu não sou inteiramente certo o que o raciocínio por trás PyString_Decode trabalhar desta maneira é. A muito antiga linha em python-dev parece indicar que ele tem algo a ver com o encadeamento a saída, mas desde que os métodos Python não fazer o mesmo, eu não tenho certeza se isso ainda é relevante.

Respondeu 18/10/2008 em 20:59
fonte usuário

votos
3

Você não quer para decodificar a seqüência em uma representação Unicode, você só quer tratá-lo como um array de bytes, certo?

Basta usar PyString_FromString:

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

Isso é tudo. Agora você tem um Python str()objeto. Veja docs aqui: https://docs.python.org/2/c-api/string.html

Estou um pouco confuso sobre como especificar "str" ou "unicode". Eles são bastante diferentes se você tiver caracteres não-ASCII. Se você quiser decodificar uma string C e você sabe exatamente o conjunto de caracteres que se encontra, então sim, PyString_DecodeStringé um bom lugar para começar.

Respondeu 17/10/2008 em 21:00
fonte usuário

votos
2

Tente chamar PyErr_Print()na " if (!py_string)cláusula". Talvez a exceção python vai lhe dar mais algumas informações.

Respondeu 17/10/2008 em 21:47
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more