問題
UTF-16エンコーディング(UCS2)でMSSQL Server 2005データベースを操作するには、Pythonで記述されたスクリプトを使用します。 このスクリプトは、次の一連のツールを使用してデータベースを操作します。
- unixODBC
- フリート
- pyodbc
- sqlachemy
そして、ここで問題が発生しました:データベース(nvarchar、ntextフィールド)から文字列データを受信すると、Unicodeが正しく処理されません。
結局のところ、私がインストールしたpythonはUCS4 unicodeでビルドされました。 PythonアセンブリでUnicode型を取得する方法は、stackoverflowに関するこの質問で詳しく説明されています。 つまり、ターミナルで次の行を実行すると:
python -c "import sys;print 'UCS4' if sys.maxunicode > 65536 else 'UCS2'"
次に、Python用のユニコードアセンブリバージョンを取得します。私の場合はUCS4でした。 これがそれ自体を引き付けるもの:
- 対応するデータベース関数を付録Wで呼び出すunixODBC(たとえば、 SQLExecDirectW() )が結果を取得します。 テキストの1文字が2バイトを占める(UCS2)
- pyodbcはODBCドライバーから結果を受け取り、その結果をUnicode変数に保存します
- したがって、pyodbcによると、結果の1文字は4バイト(UCS4)です。 これが結果の保存方法です。 ODBCドライバーから取得します。
ドライバーは、文字が2バイトを占めるデータを返し、pyodbcはこのデータを再実行して、文字が4バイトを占めるようにします。 変換が行われた場合はすべて問題ありませんが、データは単純にバイト配列としてUnicode型の変数に保存されますが、これは不快な結果をもたらします:結果文字には、基本的にODBCドライバーによって返された結果の2文字が含まれます。
ひどい結果ではありませんでしたが、私は結果を決定し、独立して変換し、シンボルで分割しました:
def odbcUCS4toUCS2(ustr): u = u"" for i in range(0, len(ustr)): u32 = ord(ustr[i]) u16 = [(u32 & 0xFFFF0000) >> 16, (u32 & 0x0000FFFF)] u += unichr(u16[1]) u += unichr(u16[0]) return u
これは十分ではありませんでした。 別の不快な結果がありました:結果の文字の長さが奇数の場合、結果の最後の文字が切り捨てられます。 つまり 文字列'this word'は、スクリプトで'this words'として受信されます 。 変換ではこの問題を解決できませんでした。Unicodeストレージが正しくないため、結果の最後の2バイトは実際にはありません。 次に、UCS2 Unicodeサポートを使用してPythonを再構築することにしました。
解決策
オプション--enable-unicode = ucs2で指定することを忘れないでください。 新しいpythonをビルドするときは、zlib1g-devパッケージをインストールすることを忘れないでください。そうしないと、pipを使用したパッケージのインストールに問題が生じる可能性があります。
virtualenvをインストールして構成します。
$ sudo apt-get install virtualenv $ virtualenv ~/ucs2env -p [ ucs2 ]
さて、エイリアスを追加します。
echo "alias ucs2env='source ~/ucs2env/bin/activate'">>~/.bashrc
まあ、それだけです。 これで、データベースに保存されているのと同じ方法でデータが取得されます。
$ ucs2env (ucs2env)$ python -c "import sys;print 'UCS4' if sys.maxunicode > 65536 else 'UCS2'" UCS2