كيفية تحويل سلسلة C (صفيف char) إلى سلسلة بيثون عندما يكون هناك أحرف غير ASCII في السلسلة؟

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

سؤال

لقد قمت بتضمين مترجم بيثون في برنامج C. لنفترض أن برنامج C يقرأ بعض البايتات من ملف إلى صفيف Char ويتعلم (بطريقة ما) أن البايتات تمثل النص مع ترميز معين (على سبيل المثال ، ISO 8859-1 أو Windows-1252 أو UTF-8). كيف يمكنني فك تشفير محتويات صفيف Char في سلسلة Python؟

يجب أن تكون سلسلة Python بشكل عام من النوع unicode- على سبيل المثال ، أ 0x93 في Windows-1252 ، يصبح المدخلات المشفرة u'\u0201c'.

لقد حاولت الاستخدام PyString_Decode, ، لكنه يفشل دائمًا عندما يكون هناك أحرف غير ASCII في السلسلة. إليك مثال يفشل:

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

رسالة الخطأ هي UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128), مما يشير إلى أن ascii يتم استخدام الترميز على الرغم من أننا نحدد windows_1252 في الدعوة إلى PyString_Decode.

الرمز التالي يعمل حول المشكلة باستخدام PyString_FromString لإنشاء سلسلة بيثون من البايتات غير المشفرة ، ثم استدعاءها 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;
}
هل كانت مفيدة؟

المحلول

Pystring_decode يفعل هذا:

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 ، يفعل بشكل أساسي ما تفعله في مثالك الثاني - يتحول إلى سلسلة ، ثم فك تشفير السلسلة. تنشأ المشكلة هنا من pystring_asdecodedString ، بدلاً من pystring_asdecodedObject. Pystring_asdecodedString يقوم pystring_asdecodedobject ، ولكن بعد ذلك يحاول تحويل كائن Unicode الناتج إلى كائن سلسلة مع الترميز الافتراضي (بالنسبة لك ، يبدو أن هذا ASCII). هذا هو المكان الذي فشل فيه.

أعتقد أنك ستحتاج إلى إجراء مكالمتين - ولكن يمكنك استخدام pystring_asdecodedObject بدلاً من استدعاء طريقة "فك الشفرة" Python. شيء مثل:

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

لست متأكدًا تمامًا مما هو السبب وراء عمل Pystring_Decode بهذه الطريقة. أ موضوع قديم جدا على بيثون ديف يبدو أنه يشير إلى أنه له علاقة بسلاسل الإخراج ، ولكن نظرًا لأن أساليب Python لا تفعل الشيء نفسه ، لست متأكدًا مما إذا كان ذلك لا يزال ذا صلة.

نصائح أخرى

أنت لا تريد فك تشفير السلسلة في تمثيل Unicode ، فأنت تريد فقط معاملتها كمجموعة من البايتات ، أليس كذلك؟

فقط استخدم PyString_FromString:

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

هذا كل شئ. الآن لديك بيثون str() هدف. انظر المستندات هنا: https://docs.python.org/2/c-api/string.html

أنا مرتبك قليلاً حول كيفية تحديد "Str" أو "Unicode". فهي مختلفة تمامًا إذا كان لديك شخصيات غير ASCII. إذا كنت تريد فك تشفير سلسلة C و أنت تعرف بالضبط ما هي الشخصية التي تم تعيينها ، ثم نعم ، PyString_DecodeString هو مكان جيد للبدء.

حاول الاتصال PyErr_Print() في ال "if (!py_string)"بند. ربما يعطيك استثناء بيثون بعض المعلومات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top