9 Stimmen

Sauberer Weg, um Python 3 Unicode in std::string umzuwandeln

Ich wickle viel C++ über die Python 2 API (Ich kann aus verschiedenen technischen Gründen nicht Dinge wie swig oder boost.python verwenden). Wenn ich einen String (normalerweise einen Pfad, immer ASCII) nach C/C++ übergeben muss, verwende ich etwas Ähnliches wie das hier:

std::string file_name = PyString_AsString(py_file_name); 
if (PyErr_Occurred()) return NULL; 

Jetzt überlege ich, auf Python 3 zu aktualisieren, wo die PyString_*-Methoden nicht existieren. Ich habe eine Lösung gefunden, die besagt, dass ich etwas Ähnliches tun sollte wie das hier:

PyObject* bytes = PyUnicode_AsUTF8String(py_file_name);
std::string file_name = PyBytes_AsString(bytes); 
if (PyErr_Occurred()) return NULL; 
Py_DECREF(bytes); 

Allerdings sind das doppelt so viele Zeilen und es scheint ein wenig hässlich zu sein (und nicht zu vergessen, dass es einen Speicherleck verursachen könnte, wenn ich die letzte Zeile vergesse).

Die andere Option besteht darin, die Python-Funktionen neu zu definieren, um mit bytes-Objekten zu arbeiten, und sie so aufzurufen:

def some_function(path_name):
    _some_function(path_name.encode('utf8'))

Das ist nicht schrecklich, erfordert jedoch einen Python-seitigen Wrapper für jede Funktion.

Gibt es eine sauberere Möglichkeit, damit umzugehen?

5voto

Shep Punkte 7396

Es scheint, dass die Lösung in Python 3.3 besteht, mit char* PyUnicode_AsUTF8(PyObject* unicode). Dies sollte genau das gleiche Verhalten wie die PyString_AsString() Funktion aus Python 2 sein.

1voto

Mats Petersson Punkte 123984

Wenn Sie wissen (und natürlich könnten Sie mit einem assert oder ähnlichem überprüfen), dass es sich alles um ASCII handelt, könnten Sie es einfach so erstellen:

std::string py_string_to_std_string(PyUnicode_string py_file_name)
{
    len = Länge von py_file_name;     // Ich bin mir nicht sicher, wie man das in Python schreibt.
    std::string str(len); 
    for(int i = 0; i < len; i++)
        str += py_file_name[i]; 
    return str;
}

1voto

Arty Punkte 12114

Stellen Sie eine verbesserte Version der akzeptierten Antwort bereit, anstatt PyUnicode_AsUTF8(...) zu verwenden, ist es besser, PyUnicode_AsUTF8AndSize(...) zu verwenden.

Weil der String möglicherweise ein Nullzeichen (Codepunkt 0) irgendwo in der Mitte enthält, wird Ihre resultierende std::string eine abgeschnittene Version des vollständigen Strings enthalten, wenn Sie PyUnicode_AsUTF8(...) verwenden.

Py_ssize_t size = 0;
char const * pc = PyUnicode_AsUTF8AndSize(obj, &size);
std::string s;
if (pc)
    s = std::string(pc, size);
else
    // Fehler, behandeln!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X