使用Delphi 2007解码UTF-8编码的西里尔文

4

我正在使用Delphi 2007(不支持Unicode),并从Google Analytics API检索XML和JSON数据。以下是一些UTF-8编码的数据,我获取了一个URL引荐路径:

ga:referralPath=/add/%D0%9F%D0%B8%D0%B6%D0%B0%D0%BC

当我使用这个解码器对其进行解码时,它会正确生成以下内容:

ga:referralPath=/add/Пижам

在Delphi 2007中有没有可以执行此解码的函数?

更新: 这些数据对应于一个URL。最终我想要做的是将其存储在SqlServer数据库中(开箱即用 - 没有修改有关字符集的设置)。然后能够创建一个HTML页面,并且链接到此页面(注意:在此示例中我仅处理url引荐路径 - 显然需要源来创建有效的url链接)。


那为什么不直接将原始编码的URL存储为它本身,而不是解码它呢? - Remy Lebeau
是的 - 那最终就是我做的。 - M Schenkel
2个回答

6
D2007支持Unicode,但不如D2009+支持得全面。在D2007中,使用WideString和少量RTL支持函数来处理Unicode。
URL包含百分号编码的UTF-8字节八位组。只需将这些序列转换为它们的二进制表示,然后使用UTF8Decode()将UTF-8数据解码为WideString即可。例如:
function HexToBits(C: Char): Byte;
begin
  case C of
    '0'..'9': Result := Byte(Ord(C) - Ord('0'));
    'a'..'f': Result := Byte(10 + (Ord(C) - Ord('a')));
    'A'..'F': Result := Byte(10 + (Ord(C) - Ord('A')));
  else
    raise Exception.Create('Invalid encoding detected');
  end;
end;

var
  sURL: String;
  sWork: UTF8String;
  C: Char;
  B: Byte;
  wDecoded: WideString;
  I: Integer;
begin
  sURL := 'ga:referralPath=/add/%D0%9F%D0%B8%D0%B6%D0%B0%D0%BC';
  sWork := sURL;
  I := 1;
  while I <= Length(sWork) do
  begin
    if sWork[I] = '%' then
    begin
      if (I+2) > Length(sWork) then
        raise Exception.Create('Incomplete encoding detected');
      sWork[I] := Char((HexToBits(sWork[I+1]) shl 4) or HexToBits(sWork[I+2]));
      Delete(sWork, I+1, 2);
    end;
    Inc(I);
  end;
  wDecoded := UTF8Decode(sWork);
  ...
end;

C - Ord('0'); 上会出现“运算符不适用于此操作数类型”的编译错误。 - M Schenkel
通过将 C 的强制转换引用转换为 **ord(C)**,使其编译成功。 - M Schenkel
就编程而言,我更喜欢使用 ord(C-'0')。 - David Heffernan
哦,我以为你可以对字符类型执行算术运算。显然不行。 - David Heffernan
@DavidHeffernan - 看到你在这些事情上失败对我的自尊心有莫大的好处,谢谢 :-) - Leonardo Herrera
显示剩余2条评论

1
您可以使用以下代码,该代码使用Windows API:
function Utf8ToStr(const Source : string) : string;
var
  i, len : integer;
  TmpBuf : array of byte;
begin
  SetLength(Result, 0);
  i := MultiByteToWideChar(CP_UTF8, 0, @Source[1], Length(Source), nil, 0);
  if i = 0 then Exit;
  SetLength(TmpBuf, i * SizeOf(WCHAR));
  Len := MultiByteToWideChar(CP_UTF8, 0, @Source[1], Length(Source), @TmpBuf[0], i);
  if Len = 0 then Exit;

  i := WideCharToMultiByte(CP_ACP, 0, @TmpBuf[0], Len, nil, 0, nil, nil);
  if i = 0 then Exit;

  SetLength(Result, i);
  i := WideCharToMultiByte(CP_ACP, 0, @TmpBuf[0], Len, @Result[1], i, nil, nil);
  SetLength(Result, i);
end;

转换为ANSI最好是可疑的。你肯定想坚持使用Unicode。 - David Heffernan
使用Unicode肯定是更好的选择。但是M Schenkel似乎需要ANSI输出。 - Nickolay Olshevsky
我不太清楚。无论如何,UTF8Decode比你的代码简单得多,而简单的WideString->字符串赋值会将UTF16->ANSI。 - David Heffernan
此代码首先将存储在字符串中的UTF-8编码数据转换为UTF-16(实际上,为了使代码更清晰,输入应该是字节数组),然后再将其转换为ANSI代码页。 - Nickolay Olshevsky
1
我知道这段代码的作用,但我告诉你它过于复杂了。你的整个答案可以压缩成两行代码。 - David Heffernan
当然,它可以被压缩,但我忘记了UTF8Decode()在D2007中的工作方式。 - Nickolay Olshevsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接