2010年06月04日

CentOSでSJISを使う

WindowsCentOSでちょっとした連携をする仕組みを作っていたのですが、困ったのが文字コードの違い。WindowsがSJISを使っているのに対してCentOSのデフォルトではUTF8を使っています。

本気で対応するのであればCentOS側のプログラムでSJIS-UTF8の変換をすべきなのですが、今回は期間限定お試しのため、安易にCentOS側のロケールをSJISにすることにした…のですが、CentOSってデフォルトではSJISロケール入ってないんですね。(今さら知りました…)

と言うことで、SJISロケールの追加方法。
localedef -f SHIFT_JIS -i ja_JP ja_JP.SJIS

これだけでOK。
コマンド実行時に、日本語ロケールだと
キャラクタマップ `SHIFT_JIS' は ASCII 互換ではありません, ロケールは ISO C に従っていません

また英語ロケールだと
character map `SHIFT_JIS’ is not ASCII compatible, locale not ISO C compliant

という警告が出ますが、気にしなくて大丈夫のようです。

私はファイルの編集にviを使うので、viでもSJISを扱えるように.exrcに以下の1行を追加します。
set fileencodings=utf8,cp932,latin

以下のサイトを参考にさせていただきました。(ありがとうございます!)

SJIS ロケールの追加 - kamata-net.com
http://blog.kamata-net.com/archives/000076.html

CentOSのlocaleにSJISを追加 - 脳ログ - livedoor Wiki(ウィキ)
http://wiki.livedoor.jp/yoko00068/d/CentOS%A4%CElocale%A4%CBSJIS%A4%F2%C4%C9%B2%C3

ずんWiki - vim
http://www.kawaz.jp/pukiwiki/?vim
posted by 月水和尚 (とも) at 10:48 | Comment(10) | TrackBack(0) | Linux(ディストリビューション固有)
この記事へのコメント
LinuxでSJISを使いたいという事は良く聞くのきですが、具体的にどのようなツールでSJISを使う必要があるのでしょうか?

Linuxで使用されているOSSの場合、ソフト毎に独自にマルチバイト対応していたりするので、glibc で SJISロケール対応してもSJISを正しく使えないツールがあると思います。

どういった場合に、glibc で SJISロケール対応するだけで良いのか気になっています。
Posted by moriyama at 2010年06月04日 13:48
moriyamaさん

今回はちょっと事情が特殊で、

・研修の課題(出題側です)なので出来るだけ単純な作りにしたい
・使用する通信ミドル、DBMSともにSJIS利用に問題なし
・Linux側は数本のプログラム(研修課題)を作るだけ

という状況だったので、安易にLinux側のロケールをSJISにすることで対応しました。もっと恒久的に動かす仕組みで、開発時間がきちんと取れるのであればLinux側はUTF8で扱いたいのですが…。

ちなみに私はUNIXでのシステム開発に一番関わっていたのがAIX 4.3.3の時代なので、ロケールをSJISにすることにはそれほど抵抗がなかったりします。それでも、完全にSJISロケールでLinuxサーバを動かす事にはさすがに抵抗がありますが。(上記の環境も、SJISロケールにしているのは開発用ユーザのログインシェルだけで、システム全体はUTF8で動かしています)
Posted by tomo at 2010年06月05日 11:52
tomo さん、説明ありがとうございます。

SJISを利用できるものだけを利用しているという事ですね。具体的なケースを教えていただき少しですがLinuxでのSJISの利用のされかたが理解できるようになってきました。

ちなみに、プログラミング言語は Java でしょうか?
よろしくお願いいたします。
Posted by moriyama at 2010年06月05日 16:55
moriyamaさん

言語はWindows側がC++(VC++2010)、サーバ側がC(gcc)です。
Javaだと内部的な文字コードはプラットフォームに関わらずUTFだった気がするのですが、どうでしたっけ?
Posted by tomo at 2010年06月05日 22:32
gccだと -finput-charset=cp932 -fexec-charset=cp932 オプションをつけてコンパイルしないとSJISの文字列リテラルは扱えなかったと思います。(表などSJISの2バイト目が 0x5C の文字が正しく扱えない)

あと、mbstowcs(3) でワイド文字に変換して扱う際には、glibc の sjis では変換でいわゆる機種依存文字が変換できませんね。それに半角の \ (0x5C) が U+00A5 に変換されてしまうのでトラブルの元になります。

詳しく検証はしていせんが、localedef を次のようにした方が良いかもしれません。

# localedef -f WINDOWS-31J -i ja_JP ja_JP.SJIS

JavaはUnicodeで処理しますがソースコードをSJISとかで書くことができたような。
Posted by moriyama at 2010年06月06日 11:18
moriyamaさん

おぉぉ、0x5Cを含むダブルバイト文字ってgccのオプションでちゃんと解釈できるんですね。前述のAIX4.3.3時代にこの問題にはよく悩まされ、仕方がないのでダメ字(0x5Cの含まれる文字をそう呼んでいましたw)のリストを手元に置き、使いたいときには明示的にエスケープして(「画面に表\示」という感じで)対応してました。積年の課題が1つ解決してすっきりしました。ありがとうございます!

localedef -f WINDOWS-31Jも試してみたのですが、こちらはvi(vim)上で文字化けが起きるようになってしまいました。テキスト自体もさることながら、vi自身の表示(ステータスとか)も化けてしまったところを見ると、エンコーディング云々の問題ではないようです。vi自身の問題か、Teraterm側の問題か、それとも何か設定が足りていないのか。

ありがとうございました!
Posted by tomo at 2010年06月07日 10:55
~/.vimrc などに、次のように記述してもダメですか?

if v:lang =~ "^ja_JP.SJIS"
set encoding=cp932
set fileencodings=cp932
endif

これでダメなら、vim のソースコードをみて直してしまった方がはやいかもしれません。

あと文字コードの自動判定は、原理的に文字コードの判定ミスを防ぐことは不可能ですから、どういうケースで判定ミスをするのか理解していない場合は、使うべきではないでしょう。

vim で、

set fileencodings=utf8,cp932,latin

という設定をした場合、ASCIIだけのテキストを開くとutf8のファイルとして確定してしまうため、日本語を追加して保存すると utf8 で保存されるという問題もありますね。
Posted by moriyama at 2010年06月07日 21:07
残念ながらfileencodingにcp932を入れてもwindows-31jを入れてもダメでした。今回の使い方なら大きな問題にならないと思うので追求はここまでにしておきたいと思います。

新規作成の時の文字コードは考えていませんでした。今回は基本的にSJIS(CP932)しか使わないつもりなので、

set fileencodings=cp932,utf8,latin

とした方が良さそうですね。いっそutf8は抜いてしまってもよいかも。

ありがとうございました。
Posted by tomo at 2010年06月08日 10:30
localedef -f WINDOWS-31J -i ja_JP ja_JP.SJIS に設定すると、CentOS 5.5 の vim は encoding を latin に設定するようですので、set encoding=cp932 の設定が必要になります。

あと vim は localedef -f SHIFT_JIS -i ja_JP ja_JP.SJIS の設定の時には LANG=ja_JP.SJIS で、内部エンコーディングを sjis に設定してしまいます。内部エンコーディングが sjis だと utf8 などへの文字コード変換で \ が U+00A5 に変換されるという問題が発生してしまいます。

この問題を回避するためにも set encoding=cp932 という設定が必要になってきます。ちなみに fencodings の設定ではないので注意してください。

LinuxでのSJISロケールは、こういう問題をきちんと理解して使うべきもので手間を省きたいということで安易に使うべきではないと考えています。
Posted by moriyama at 2010年06月08日 13:17
moriyamaさん

encoding=cp932を設定することで正常に動作することを確認いたしました。

本件以前のコメントでご指摘いただいているにもかかわらず、encodingをfileencodingと勘違いして設定をしておりました。申し訳ございません。

べき論として、SJISロケールを安易に使うべきではないというのはその通りだと思うのですが、今回は研修の課題という本来の目的に出来るだけ集中できるよう、文字コードに関しては(今回の環境で)最も取り扱いやすいSJIS(cp932)に統一して使うつもりです。

ご指導ありがとうございました。
Posted by tomo at 2010年06月08日 13:44
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。