bytesからchar*への変換
python3のマルチバイト文字列であるところのbytearraybytesをcのchar buf[20]に代入したい。
textbuffer.h
struct TextBuffer { TextBuffer(); char buf[20]; };
textbuffer.cpp
TextBuffer::TextBuffer() { }
textbuffer.i
%module textbuffer %{ #include "textbuffer.h" } %include "textbuffer.h"
setup.py
# coding: utf-8 from distutils.core import setup, Extension import os import sys setup( name='textbuffer', version='0.1', description='textbuffer module', ext_modules=[ Extension( '_textbuffer', [ 'textbuffer.i', 'textbuffer.cpp', ], swig_opts=['-c++'], ), ], py_modules=['textbuffer'], )
# python3 setup.py build
build/lib.win32-3.1/textbuffer.pyを使う
>>> a=textbuffer.TextBuffer() >>> a.buf="abc" >>> print(a.buf) abc # bytearrayの代入でエラー >>> a.buf="abc".encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "textbuffer.py", line 71, in <lambda> __setattr__ = lambda self, name, value: _swig_setattr(self, TextBuffer, name , value) File "textbuffer.py", line 48, in _swig_setattr return _swig_setattr_nondynamic(self,class_type,name,value,0) File "textbuffer.py", line 41, in _swig_setattr_nondynamic if method: return method(self,value) TypeError: in method 'TextBuffer_buf_set', argument 2 of type 'char [20]' >>>
解決
細かいことは良くわからないがとりあえず動く方法。
const char *を引数に取るセッターを追加して、それに対するbytearrayからのtypemapを設定することでできるようだ。
textbuffer.iに追加
// bytearrayからconst char *へのtypemap %include <pybuffer.i> %pybuffer_string(const char *src); // setを追加 %{ #include <string.h> %} %extend TextBuffer { void set(const char *src) { strncpy(self->buf, src, 20); } };
動作確認
>>> import textbuffer >>> a=textbuffer.TextBuffer() >>> a.set("abc".encode("ascii")) >>> print(a.buf) abc # CP932でやってみる(CP932->PyUnicodeで失敗してる) >>> a.set("日本語".encode("cp932")) >>> print(a.buf) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'utf8' codec cant decode byte 0x93 in position 0: unexpected code byte # UTF-8でやってみる(問題なし) >>> a.set("日本語".encode("utf-8")) >>> print(a.buf) 日本語 >>>
python3+swigでは素では
str <-> const char *(utf-8)
str <-> const wchar_t *(unicode)
が基本。
それ以外だと
str.encode('cp932') -> const char*(pybuffer_string等で変換指定)
というようながんばりが必要みたいだ。
文字コードとの戦いは果てしない。
pybuffer_string
についてはこの辺参考。
http://www.swig.org/Doc1.3/Python.html#Python_nn75
そろそろswigのtypemapをちゃんと理解したいところだな。