フォーラム


ゲスト  

ようこそ ゲスト さん。このフォーラムに投稿するには 登録が必要です。

ページ: [1]
トピック: ParamStr() がおかしい
DEKO
管理者
投稿数: 2690
ParamStr() がおかしい
on: 2013/11/09 09:30 Sat

QC#119758 の関連です。

Report No: 119758 Status: Open
[MacOS] ParamStr(0) returns wrong string on MacOS (UTF-8 problem)
http://qc.embarcadero.com/wc/qcmain.aspx?d=119758
QCWIN:Defect_No=119758

 
この QC の Workaround には

  UTF8ToString(RawByteString(ParamStr(0)))

 
とありますが、実はこれだけでは問題は解決しません。

OS X のコマンドライン引数は UTF-8 になっています…なので、System.ParamStr() の

function ParamStr(Index: Integer): string;
{$IFDEF MSWINDOWS}

...

{$ENDIF MSWINDOWS}
{$IF defined(LINUX) or defined(MACOS)}
begin
if Index < ArgCount then
Result := string(PAnsiCharArray(ArgValues^)[Index])
else
Result := '';
{$ENDIF LINUX or MACOS}
end;

 
これではマズい事が解ります。

OS X で 現行の ParamStr() が返すのは、UTF-8 を ANSI (日本なら SHIFT_JIS) へ変換したものを UnicodeString へ変換したものです。Workaround は このヘンテコな UnicodeString を ANSI (日本なら SHIFT_JIS) へ変換したものを UTF-8 へ変換しますが、ANSI が噛んでいる時点で、ANSI に存在しない文字…例えば結合文字等は失われてしまいます。つまり、ParamStr() が返した値をどんなにいじっても正しい文字列は取得できない事になります。

解決方法は、ParamStr() の QC が修正されるまでは以下の関数を使う事です。

function ParamStr_OSX(Index: Integer): string;
type
PAnsiCharArray = array [0..0] of PAnsiChar;
begin
if Index < ArgCount then
Result := string(UTF8String(PAnsiCharArray(ArgValues^)[Index]))
else
Result := '';
end;

 
このコードでは、コマンドライン引数 (UTF-8) を UTF8String へ格納し、それを UnicodeString へ変換して返しています。すべて Unicode で処理していますのでロスレス変換となり、文字化けは発生しません。

Workaround の方法はラウンドトリップ変換でしかないので、すべての問題を解決するには至りません。OS X のファイル名は "オレオレ NFD" で正規化されているため、ラウンドトリップだと濁点等は失われてしまいます。Unicode のみを使ったロスレス変換であれば、正規化はそのままに UnicodeString で取得できます。

See also:

Macで実行ファイルのフォルダの取得方法 (Delphi Q&A)
http://hpcgi1.nifty.com/MADIA/DelphiBBS/wwwlng.cgi?print+201311/13110006.txt

[MacOS] ParamStr(0) returns wrong string on MacOS (UTF-8 problem)
http://qc.embarcadero.com/wc/qcmain.aspx?d=119758

DEKO
管理者
投稿数: 2690
Re: ParamStr() がおかしい
on: 2014/04/16 14:20 Wed

この件は XE6 で解決されています。

ページ: [1]
WP Forum Server by ForumPress | LucidCrew
バージョン: 1.7.5 ; ページロード: 0.023 sec.