SOにはこのような別の質問があると思いましたが、特にC共有ライブラリモジュールに対してです。この答えはそこでより適切だったかもしれませんが、今はリンクが見つかりません:)
簡単に言えば、私の答えは -locale.setlocale(locale.LC_ALL, '')
モジュールをロードする前に試してください (私cmd
自身はまだ使用していません)。さらに詳細に:
Subversion (SVN) 用の SWIG Python バインディングを使用しようとしていました。これらは基本的に、SVN C ライブラリ コードから直接、SWIG によって作成された Python 用の自動インターフェイスです ( libsvn1
)。ターミナルから実行すると、コードsvn status MyWorkingCopy
にフックされlibsvn
ます-そして、何年も失敗していません(そのリポジトリの場合)。しかし、同じ端末から Python の例 (と同じことを行うsvn status
) を実行すると (同じコードにフックされます) libsvn
、libsvn/SWIG から UTF-8 関連のエラーが発生し、Python スクリプトがクラッシュします。 .
これは、Python が何らかの形でライブラリに「影響」を与え、文字セットに関して別の動作をさせたことを意味します。しかし、私の端末は永続的に報告します:
$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
...
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
したがって、ターミナル/シェル (bash
この場合) が何を考えているかではなく、基礎となる C コード (libsvn
この場合は) が現在の設定についてどう考えているかが重要です。そして、同じことがpythonにも当てはまると思いました:
$ python -c 'import locale; print locale.getdefaultlocale()'
('en_US', 'UTF-8')
そこで、ターミナルから実行した場合と Python から実行した場合 (同じターミナル内) で、C コードが何を認識するかを確認します。さらにデバッグすると、実際にはSVNがメモリ割り当てに使用するlibsvn
別のライブラリ(Apache Portable Runtime)からのものであることが判明しました。libapr
私がやったことは、スタンドアロンのCプログラムlibsvn
で使用する文字列のコピーの繰り返しを書くことです。libapr
次に、SWIG を介して Python モジュールとしてビルドしました。このプログラムaprtest
は、文字列を引数として受け取り、libapr
エンジンを呼び出してそれをコピーし、結果を表示します。そのソースはここに投稿されています:
私が使用したライブラリのバージョン (Ubuntu 11.04)については、スクリプトbuild-aprtest.shを参照してください。ビルドするには、実行しますbash build-aprtest.sh
。
ここで、このようにビルドされた実行可能ファイルをターミナルで実行すると、次のようになります。
$ locale
LANG=en_US.UTF-8
...
$ ./aprtest "test"
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 0
(*dest)->data: test
$ ./aprtest "test東京"
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 22
端末のlibapr
報告にもかかわらず、エンジンはコマンドラインからの UTF-8 入力で明らかに失敗しましたUTF-8
。aprtest_s
そして、 Python を介して共有モジュール (と呼ばれる) として実行すると、次のようになります。
$ python -c 'import aprtest_s; aprtest_s.pysmain("test")'
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 0
(*dest)->data: test
$ python -c 'import aprtest_s; aprtest_s.pysmain("test東京")'
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 22
...同じことが起こります(ところで、SVNとAPRの同じ問題については、Perlについては、ネイティブプラットフォームエンコーディングを返す変数または関数があります(APR_LOCALE_CHARSET)を参照してください)。したがって、次のように結論付けることができます。
- C プログラムが端末から直接実行されているか、Python を介して実行されているかは問題ではありません。C プログラムは、呼び出し元のプログラムとは異なるロケール/エンコーディング設定を参照するだけです。
- ASCII 文字列では問題ありません。UTF-8 文字列のみです。
では、どうすれば svn クライアントが端末から適切に動作し、最終的libapr
にクラッシュすることなく使用できるのでしょうか? さて、 aprtest_s.cのソースのコメントを見ることができます。それは、プログラムの独自のロケールを設定することであり、C 関数を使用して、プロセスのロケールのすべてのカテゴリをsetlocale(LC_CTYPE,"")
設定します。この問題は、実際にはapr-dev メーリング リストで言及されています: Re: Misbehavior of apr_os_locale_encoding on Windows :
... この 55 の異なる現在のロケールの 1 つを選択することは、おそらく APR ではなく、アプリケーションによってのみ適切に行うことができます。
したがって、C アプリケーションでコーディングsetlocale()
することにより、明らかにデフォルトのロケールを明示的に選択するので、それをlibapr
認識しています。テスト ケースでは、この への呼び出しは へsetlocale
の呼び出しの前に発生する必要がありapr_xlate_open
ます。
さて、投稿されたバージョンのaprtest
は を実行しないので、Python バージョンを使用すると、Pythonsetlocale
から何が起こっているかを確認できます (これlocale.setlocale()
にも注意してください) 。
$ PYTHONIOENCODING='utf-8' echo 'import sys;print sys.stdin.encoding' | python
None
$ echo 'import sys;print sys.stdin.encoding' | PYTHONIOENCODING='utf-8' python
utf-8
$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
...
$ python
Python 2.7.1+ (r271:86832, Sep 27 2012, 21:16:52)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import aprtest_s
>>> aprtest_s.print_locale()
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
>>> aprtest_s.pysmain("test")
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 0
(*dest)->data: test
>>> aprtest_s.pysmain("test東京")
LC_CTYPE 0 CODESET 14
ANSI_X3.4-1968
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 22
>>> import locale
>>> print locale.getdefaultlocale()
('en_US', 'UTF-8')
>>> print locale.getlocale()
(None, None)
>>> import sys
>>> print sys.stdin.encoding
UTF-8
>>> locale.setlocale(locale.LC_ALL, '')
'en_US.UTF-8'
>>> print sys.stdin.encoding
UTF-8
>>> print locale.getlocale()
('en_US', 'UTF-8')
>>> aprtest_s.pysmain("test")
LC_CTYPE 0 CODESET 14
UTF-8
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 0
(*dest)->data: test
>>> aprtest_s.pysmain("test東京")
LC_CTYPE 0 CODESET 14
UTF-8
apr_xlate_open: apr_err=0
apr_xlate_conv_buffer apr_err == 0
(*dest)->data: test東京
>>>
したがって、C アプリケーションが Python で見ているものを確認するには、locale.getlocale()
( NOTlocale.getdefaultlocale()
) を使用します。私が今理解している方法では、デフォルトと見なされるが、アプリケーションの起動時に必ずデフォルトとして適用さgetdefaultlocale
れる、どこかに保存されたいくつかの OS/ユーザー設定を返します。現在適用されている実際のロケール設定を取得します。そして、空の文字列で呼び出すと、コードの残りの部分が次のようになると思います: デフォルト設定 ( で指定されたもの) を読み取り、デフォルト設定を現在の設定として適用します。getlocale
setlocale
getdefaultlocale
最後に、関連しているように見えますが、stdin
/のエンコーディング設定はstdout
(明らかに) 現在のロケールのエンコーディングとは何の関係もありません (少なくとも、その環境で実行されている C プログラムから見れば)。
これが誰かに役立つことを願っています、
乾杯!