将包含转义组合变音符号(如“Fu\u0308rst”)的 Delphi XE AnsiString 转换为友好的 WideString“Fürst”的最佳方法是什么?
我知道这并不总是适用于所有组合,但是应该支持常见的拉丁语块,而无需自己构建愚蠢的转换表。我想可以在新的 Characters 单元的某个地方找到解决方案,但我不明白。
将包含转义组合变音符号(如“Fu\u0308rst”)的 Delphi XE AnsiString 转换为友好的 WideString“Fürst”的最佳方法是什么?
我知道这并不总是适用于所有组合,但是应该支持常见的拉丁语块,而无需自己构建愚蠢的转换表。我想可以在新的 Characters 单元的某个地方找到解决方案,但我不明白。
我认为您需要执行Unicode 规范化。在你的弦上。
我不知道 Delphi XE RTL 中是否有特定的调用来执行此操作,但 WinAPI 调用NormalizeString应该可以帮助您,使用模式 NormalizationKC:
归一化KC
Unicode 规范化形式 KC,兼容性组合。将每个基本字符和组合字符转换为规范的预组合等效字符,并将所有兼容性字符转换为其等效字符。例如,连字 fi 变成 f + i;类似地,A + ¨ + fi + n 变为 Ä + f + i + n。
这是解决我的问题的完整代码:
函数 Unescape(const s: AnsiString): 字符串; 变量 i:整数; j:整数; c:整数; 开始 // 使结果至少足够大。这可以防止过多的重新分配 SetLength(结果,长度); 我:= 1; j := 1; 而 i <= 长度确实开始 如果 s[i] = '\' 然后开始 如果 i < Length(s) 然后开始 // 转义反斜杠? 如果 s[i + 1] = '\' 然后开始 结果[j] := '\'; 公司(我,2); 结尾 // 将十六进制数转换为 WideChar else if (s[i + 1] = 'u') and (i + 1 + 4 <= Length(s)) 然后 TryStrToInt('$' + string(Copy(s, i + 2, 4)), c) 开始 公司(我,6); 结果[j] := WideChar(c); 结束否则开始 raise Exception.CreateFmt('位置 %d 处的无效代码', [i]); 结尾; 结束否则开始 raise Exception.Create('字符串意外结束'); 结尾; 结束否则开始 结果[j] := WideChar(s[i]); 公司(一); 结尾; 公司(j); 结尾; // 如果我们保留了太多空间,则修剪结果 设置长度(结果,j - 1); 结尾; 常量 归一化C = 1; 函数 NormalizeString(NormForm:整数;lpSrcString:LPCWSTR;cwSrcLength:整数; lpDstString:LPWSTR;cwDstLength:整数):整数;标准调用;外部“Normaliz.dll”; 函数 Normalize(const s: string): string; 变量 新长度:整数; 开始 // 在 NormalizationC 模式下,结果字符串不会比输入字符串长 SetLength(结果,长度); newLength := NormalizeString(NormalizationC, PChar(s), Length(s), PChar(Result), Length(Result)); 设置长度(结果,新长度); 结尾; 函数 UnescapeAndNormalize(const s: AnsiString): 字符串; 开始 结果 := Normalize(Unescape(s)); 结尾;
谢谢你们!我确信我对 StackOverflow 的第一次体验不会是我的最后一次 :-)
他们总是这样逃跑吗?总是4位数?
\ 字符本身是如何转义的?
假设 \character 被 \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);
此代码在 Delphi 2007 中进行了测试,但由于明确使用了 Ansistring 和 Widestring,它也应该在 XE 中工作。
[编辑] 代码没问题。荧光笔失败。
如果我没记错的话,Delphi XE 现在支持正则表达式。不过,我不经常使用它们,但这似乎是解析字符串然后替换所有转义值的好方法。也许有人有一个很好的例子来说明如何在 Delphi 中使用正则表达式来做到这一点?
GolezTrol,你忘了'$'
if (s[i+1] <> 'u') or not TryStrToInt('$'+Copy(s, i+2, 4), c) then