7

C プログラムに Python インタープリターを組み込みました。C プログラムがファイルから char 配列にいくつかのバイトを読み取り、そのバイトが特定のエンコーディング (ISO 8859-1、Windows-1252、または UTF-8 など) でテキストを表していることを (何らかの方法で) 学習したとします。この char 配列の内容を Python 文字列にデコードするにはどうすればよいですか?

Python 文字列は一般に、型である必要がありunicodeます。たとえば、0x93Windows-1252 でエンコードされた入力では a は になり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)、エンコーディングが使用されていることを示しています。asciiwindows_1252PyString_Decode

次のコードは、 を使用してデコードされPyString_FromStringていないバイトの Python 文字列を作成し、その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;
}
4

3 に答える 3

6

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、それは基本的に2番目の例で行っていることを行います-文字列に変換してから、文字列をデコードします。ここでの問題は、PyString_AsDecodedObject ではなく、PyString_AsDecodedString から発生します。PyString_AsDecodedString は PyString_AsDecodedObject を実行しますが、結果の Unicode オブジェクトをデフォルトのエンコーディング (ASCII のように見えます) で文字列オブジェクトに変換しようとします。そこが失敗です。

2 つの呼び出しを行う必要があると思いますが、Python の "decode" メソッドを呼び出す代わりに PyString_AsDecodedObject を使用できます。何かのようなもの:

#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-devの非常に古いスレッドは、出力の連鎖と関係があることを示しているようですが、Python メソッドは同じことをしないため、それがまだ関連しているかどうかはわかりません。

于 2008-10-18T19:59:25.153 に答える
3

文字列を Unicode 表現にデコードするのではなく、バイトの配列として扱いたいだけですよね?

使用するだけPyString_FromStringです:

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

それで全部です。これで Pythonstr()オブジェクトができました。こちらのドキュメントを参照してください: https://docs.python.org/2/c-api/string.html

「str」または「unicode」の指定方法について少し混乱しています。ASCII 以外の文字を使用している場合、それらはまったく異なります。C 文字列をデコードする必要があり、その文字セットが正確にわかっている場合PyString_DecodeStringは、はい、開始するのに適した場所です。

于 2008-10-17T20:00:47.527 に答える
2

PyErr_Print()" if (!py_string)" 節で呼び出してみてください。おそらく、Python の例外によって、さらに詳しい情報が得られるでしょう。

于 2008-10-17T20:47:20.787 に答える