2014年1月3日金曜日

FPC の 文字エンコード

Application.Exename が cp932(ansiやsjisの友達) を返していたので何故なのかと。

全部が 全部 UTF8 ではないようです。(FPC 2.6.2 + Windows 8)

フォーラムを見るとよくある話のようで、Wiki だのマニュアルだのよく読まないといけなさそうです。

LCL は UTF8 で統一されているそうですが、そうでないものに関しては、cp932 等、LConvEncoding.GetDefaultTextEncoding()と同じ charsetで文字が返ってきます。

UTF8対応のクラスや関数がある場合はそれを使い、そうでない場合は随時UTF8ToSys() を使って変換するという方針で書いていけば、とりあえずOKなようです。

UTF8非対応な環境で利用する場合も問題ないよう対策されているようです。

これらは FileUtil で宣言されているので、ファイル名関連に使ってやるとよさそうです。

FileExistsUTF8() などは UTF8文字列を渡してやります。
ソースコードが UTF8 で書かれているなら const 等の定義済み文字列もそのまま渡します。
UTF8対応クラスや関数が返す文字列もUTF8なのでそのまま渡せます。

とりあえず関数の対応状況が不明な場合はコードを辿るか {$OPT D+} や Assert() で観察したほうがよさそうです。

FileExists() を使う時は UTF8ToSys() で変換してやれば使えます。

TFileStream や TMemoryStream などは UTF8 非対応のようです。
継承してファイル名の入出力だけ SysToUTF8(), UTF8ToSys() すればいいように思います。

しかし、拡張された一部の文字が取り扱えないようです。
関連: http://forum.lazarus.freepascal.org/index.php?topic=17692.0

Application.Exename
Application.Exename はよく使われると思いますが cp932 を返してくるので  UTF8関数で利用する場合は SysToUTF8() cp932等に変換してやらねばなりません。

2回エンコードするとどうなるか
また、UTF8ToSys() や SysToUTF8()は二重にエンコードすると化けるようです。
現在の文字セットの判定はしてくれません。
コード辿れば分かる事なのですが、ansiフラグ(*1)が有効な場合と、ascii 文字列のエンコードは避けてくれるようです。

(*1):SetNeedRTLAnsi() で、ansi 固定に指定できそうに見えますが試していないので不明。

エンコードを判定するには LConvEncoding.GuessEncoding()  が利用できます。
この関数は文字セットを"cp932" や "UTF8" 等の文字列で返します。

また、LConvEncoding.GuessEncoding() は us_ascii や空文字列も utf8 と返してくるので注意が必要です。

ちなみに LConvEncoding の ConvertEncoding() 関数を使ってもエンコードできます。

0 件のコメント:

コメントを投稿