「Fu\u0308rst」のようなエスケープされた結合発音区別符号を含むDelphiXEAnsiStringを、気の利いたWideString「Fürst」に変換する最良の方法は何ですか。
これがすべての組み合わせで常に可能であるとは限らないという事実を認識していますが、一般的なラテン語のブロックは、自分で愚かな変換テーブルを作成せずにサポートする必要があります。解決策は新しいキャラクターユニットのどこかにあると思いますが、わかりません。
「Fu\u0308rst」のようなエスケープされた結合発音区別符号を含むDelphiXEAnsiStringを、気の利いたWideString「Fürst」に変換する最良の方法は何ですか。
これがすべての組み合わせで常に可能であるとは限らないという事実を認識していますが、一般的なラテン語のブロックは、自分で愚かな変換テーブルを作成せずにサポートする必要があります。解決策は新しいキャラクターユニットのどこかにあると思いますが、わかりません。
Unicode正規化を実行する必要があると思います。あなたの文字列に。
Delphi XE RTLにこれを行うための特定の呼び出しがあるかどうかはわかりませんが、WinAPI呼び出しNormalizeStringは、モードNormalizationKCでここで役立ちます。
正規化KC
KC形式のUnicode正規化、互換性構成。各ベースに加えて、結合文字を正規の合成済み同等文字に変換し、すべての互換性文字を同等のものに変換します。たとえば、合字fiはf+iになります。同様に、A+¨+?+nはÄ+f + i+nになります。
これが私の問題を解決した完全なコードです:
function Unescape(const s:AnsiString):文字列; var i:整数; j:整数; c:整数; 始める //結果を少なくとも十分に大きくします。これにより、再割り当てが多すぎるのを防ぎます SetLength(結果、長さ); i:= 1; j:= 1; i<=長さは始まります s [i] ='\'の場合、開始します i <長さの場合、開始します //バックスラッシュをエスケープしましたか? s [i + 1] ='\'の場合、開始します Result [j]:='\'; inc(i、2); 終わり //16進数をWideCharに変換します else if(s [i + 1] ='u')and(i + 1 + 4 <= Length(s)) そしてTryStrToInt('$' + string(Copy(s、i + 2、4))、c)そして開始 inc(i、6); Result [j]:= WideChar(c); 終了その他開始 Exception.CreateFmt('位置%dの無効なコード'、[i]);を発生させます。 終わり; 終了その他開始 Exception.Create('予期しない文字列の終わり');を発生させます。 終わり; 終了その他開始 Result [j]:= WideChar(s [i]); inc(i); 終わり; inc(j); 終わり; //予約したスペースが多すぎる場合は、結果をトリミングします SetLength(結果、j-1); 終わり; const NormalizationC = 1; function NormalizeString(NormForm:Integer; lpSrcString:LPCWSTR; cwSrcLength:Integer; lpDstString:LPWSTR; cwDstLength:整数):整数; stdcall; 外部'Normaliz.dll'; 関数Normalize(const s:string):string; var newLength:整数; 始める // NormalizationCモードでは、結果の文字列は入力文字列より長くなりません SetLength(結果、長さ); newLength:= NormalizeString(NormalizationC、PChar(s)、Length(s)、PChar(Result)、Length(Result)); SetLength(結果、newLength); 終わり; function UnescapeAndNormalize(const s:AnsiString):文字列; 始める 結果:= Normalize(Unescape(s)); 終わり;
皆さん、ありがとうございました!StackOverflowでの最初の経験は、私の最後の経験ではないと確信しています:-)
彼らはいつもこのように逃げていますか?常に4桁ですか?
\文字自体はどのようにエスケープされますか?
\文字が\xxxxによってエスケープされていると仮定すると、ここでxxxxは\文字のコードであり、文字列を簡単にループできます。
function Unescape(s: AnsiString): WideString;
var
i: Integer;
j: Integer;
c: Integer;
begin
// Make result at least large enough. This prevents too many reallocs
SetLength(Result, Length(s));
i := 1; j := 1;
while i <= Length(s) do
begin
// If a '\' is found, typecast the following 4 digit integer to widechar
if s[i] = '\' then
begin
if (s[i+1] <> 'u') or not TryStrToInt(Copy(s, i+2, 4), c) then
raise Exception.CreateFmt('Invalid code at position %d', [i]);
Inc(i, 6);
Result[j] := WideChar(c);
end
else
begin
Result[j] := WideChar(s[i]);
Inc(i);
end;
Inc(j);
end;
// Trim result in case we reserved too much space
SetLength(Result, j-1);
end;
このように使用します
MessageBoxW(0, PWideChar(Unescape('\u0252berhaupt')), nil, MB_OK);
このコードはDelphi2007でテストされていますが、AnsistringとWidestringを明示的に使用しているため、XEでも機能するはずです。
[編集]コードは大丈夫です。蛍光ペンが失敗します。
誤解しない限り、DelphiXEは正規表現をサポートするようになりました。ただし、あまり頻繁には使用しませんが、文字列を解析して、エスケープされたすべての値を置き換えるのは良い方法のようです。おそらく誰かが正規表現を使ってDelphiでこれを行う方法の良い例を持っていますか?
GolezTrol、あなたは「$」を忘れます
if (s[i+1] <> 'u') or not TryStrToInt('$'+Copy(s, i+2, 4), c) then