【问题标题】:Delphi XE AnsiStrings with escaped combining diacritical marksDelphi XE AnsiStrings 与转义组合变音符号
【发布时间】:2011-05-12 00:16:38
【问题描述】:

将包含转义组合变音符号(如“Fu\u0308rst”)的 Delphi XE AnsiString 转换为友好的 WideString“Fürst”的最佳方法是什么?

我知道这并不总是适用于所有组合,但应该支持常见的拉丁语块,而无需自己构建愚蠢的转换表。我想可以在新的 Characters 单元的某个地方找到解决方案,但我不明白。

【问题讨论】:

  • 据我所知,这不是任何标准的字符串格式,所以你必须自己解码。您在哪个部分遇到问题,解码转义字符或找到相应的组合字符?
  • 解码转义字符很简单;找到相应的组合字符是问题所在。但它看起来像 Roddy 建议的 WinAPI 调用 NormalizeString 为我指明了正确的方向。

标签: delphi unicode delphi-xe diacritics


【解决方案1】:

GolezTrol, 你忘了'$'

if (s[i+1] <> 'u') or not TryStrToInt('$'+Copy(s, i+2, 4), c) then

【讨论】:

  • 这应该作为对@GolezTrol 答案的评论发布,而不是作为它自己的答案。
【解决方案2】:

这是解决我问题的完整代码:

函数 Unescape(const s: AnsiString): 字符串; 变量 i:整数; j:整数; c:整数; 开始 // 使结果至少足够大。这可以防止过多的重新分配 SetLength(结果,长度); 我:= 1; j := 1; 而 i

谢谢大家!我确信我对 StackOverflow 的第一次体验不会是我的最后一次 :-)

【讨论】:

    【解决方案3】:

    如果我没记错的话,Delphi XE 现在支持正则表达式。不过,我不经常使用它们,但这似乎是解析字符串然后替换所有转义值的好方法。也许有人有一个很好的例子来说明如何在 Delphi 中使用正则表达式来做到这一点?

    【讨论】:

      【解决方案4】:

      他们总是这样逃跑吗?总是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 中工作。

      [编辑] 代码没问题。荧光笔失败。

      【讨论】:

      • 是的,但他想将 'u\u0308berhaupt' 转换为 'überhaupt'。
      • 是的,我没有很好地阅读这个问题。此代码仅将类似 C 的符号转换为“真实”字符。在此之后,您仍然应该使用 NormalizeString 来规范化字符串。这样您就可以实现所需的转换。
      • 将“\”字符转义为“\\”,便于处理。谢谢,将您的解析器与 NormalizeString 结合起来应该可以解决问题。
      • 在我的回答中对解析器所做的小改动:不要使用 s[i+1] 超出字符串长度,将 4 个字符转换为十六进制字符串并取消反斜杠本身。跨度>
      【解决方案5】:

      我认为你需要在你的字符串上执行Unicode Normalization.

      我不知道 Delphi XE RTL 中是否有特定的调用来执行此操作,但 WinAPI 调用 NormalizeString 在这里应该可以帮助您,使用模式 NormalizationKC:

      归一化KC

      Unicode 规范化形式 KC,兼容性组合。变换 每个碱基加上组合字符 规范的预先组合的等价物 和所有兼容性字符 他们的等价物。例如,连字 fi 变成 f + i;同样,A + ¨ + fi + n 变成 Ä + f + i + n。

      【讨论】:

      • 非常感谢,我去看看NormalizeString函数。
      猜你喜欢
      • 2011-07-03
      • 1970-01-01
      • 2018-01-31
      • 1970-01-01
      • 2019-07-13
      • 2011-06-09
      • 2016-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多