Как исправить 'UnicodeDecodeError: кодек' utf-8 'не может декодировать байт' при использовании расширений Python C? - PullRequest
1 голос
/ 19 мая 2019

Учитывая следующий файл bug.txt:

event "øat" not handled

Я написал следующие расширения Python C для файла fastfilewrapper.cpp

#include <Python.h>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>

static PyObject* hello_world(PyObject *self, PyObject *args) {
    printf("Hello, world!\n");
    std::string retval;
    std::ifstream fileifstream;

    fileifstream.open("./bug.txt");
    std::getline( fileifstream, retval );
    fileifstream.close();
    std::cout << "retval " << retval << std::endl;
    return Py_BuildValue( "s", retval.c_str() );
}

static PyMethodDef hello_methods[] = { {
        "hello_world", hello_world, METH_NOARGS,
        "Print 'hello world' from a method defined in a C extension."
    },
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef hello_definition = {
    PyModuleDef_HEAD_INIT,
    "hello", "A Python module that prints 'hello world' from C code.",
    -1, hello_methods
};

PyMODINIT_FUNC PyInit_fastfilepackage(void) {
    Py_Initialize();
    return PyModule_Create(&hello_definition);
}

Я собрал его с помощью pip3 install ., используяthis setup.py

from distutils.core import setup, Extension

# https://bugs.python.org/issue35893
from distutils.command import build_ext

def get_export_symbols(self, ext):
    parts = ext.name.split(".")
    if parts[-1] == "__init__":
        initfunc_name = "PyInit_" + parts[-2]
    else:
        initfunc_name = "PyInit_" + parts[-1]

build_ext.build_ext.get_export_symbols = get_export_symbols

setup(name='fastfilepackage', version='1.0',  \
      ext_modules=[Extension('fastfilepackage', ['fastfilewrapper.cpp'])])

Затем я использую этот скрипт test.py:

import fastfilepackage

iterable = fastfilepackage.hello_world()
print('iterable', iterable)

Но Python выдает это исключение, когда я запускаю скрипт test.py Python:

$ PYTHONIOENCODING=utf8 python3 test.py
Hello, world!
retval event "▒at" not handled
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    iterable = fastfilepackage.hello_world()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf8 in position 7: invalid start byte

Как я могу восстановить неправильные символы Юникода?

т.е. игнорировать эти ошибки при связывании C и Python.

При работе исключительно с Python я могу использовать это:

file_in = open( './bug.txt', errors='replace' )
line = file_in.read()
print( "The input line was: {line}".format(line=line) )

Что эквивалентно errors='replace' при связывании с Python C Extensions?

1 Ответ

1 голос
/ 19 мая 2019

Если вы хотите иметь семантическую обработку ошибок 'replace', вы должны сделать это на стороне C примерно так и вернуть ее на сторону python:

return PyUnicode_DecodeUTF8(retval.c_str(), retval.size(), "replace");

В нашем случае это будет выглядеть так:

Hello, world!
retval event "?at" not handled
iterable event "�at" not handled
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...