【问题标题】:Delphi: Encoding Strings as Python doDelphi:像 Python 一样编码字符串
【发布时间】:2011-04-09 03:54:59
【问题描述】:

我想像 Python 那样编码字符串。

Python 代码是这样的:

def EncodeToUTF(inputstr):
  uns = inputstr.decode('iso-8859-2')
  utfs = uns.encode('utf-8')
  return utfs

这很简单。

但在 Delphi 中,我不明白如何编码,首先强制使用好的字符集(不管我们拥有哪台计算机)。

我尝试了这个测试代码来查看转换:

procedure TForm1.Button1Click(Sender: TObject);
var
    w : WideString;
    buf : array[0..2048] of WideChar;
    i : integer;
    lc : Cardinal;
begin
    lc := GetThreadLocale;
    Caption := IntToStr(lc);
    StringToWideChar(Edit1.Text, buf, SizeOF(buf));
    w := buf;
    lc := MakeLCID(
        MakeLangID( LANG_ENGLISH, SUBLANG_ENGLISH_US),
        0);
    Win32Check(SetThreadLocale(lc));
    Edit2.Text := WideCharToString(PWideChar(w));
    Caption := IntToStr(AnsiCompareText(Edit1.Text, Edit2.Text));
end;

输入是:“árvíztűrő tükörfúrógép”,匈牙利口音测试短语。 本地lc为1038(hun),新lc为1033。

但这每次都会产生 0 结果(相同的字符串),并且重音相同,我不会丢失不是英语 lang 的 ŐŰ。

我做错了什么?我如何做和 Python 一样的事情?

感谢您的每一个帮助、链接等: dd

【问题讨论】:

    标签: delphi character-encoding encode utf


    【解决方案1】:

    如果您使用的是 Delphi 2009 或更新版本,来自默认 VCL 控件的每个输入都将是 UTF-16,因此无需对您的输入进行任何转换。

    如果您使用的是 Delphi 2007 或更早版本(看起来),那么您将受到 Windows 的摆布,因为 VCL 是 ANSI,而 Windows 有一个固定的代码页来确定可以在 TEdit 中使用哪些字符。

    您可以在控制面板中更改系统范围的默认 ANSI CP,但每次都需要重新启动。

    在 Delphi 2007 中,您有机会使用 TNTUnicode 控件或一些类似的解决方案将文本从 UI 获取到您的代码。

    在 Delphi 2009 及更高版本中,RTL 中还有大量 Unicode 和字符集处理例程。

    字符集之间的转换可以通过SysUtils.TEncoding来完成:

    http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_TEncoding.html

    【讨论】:

    • 无需重新启动,在这里可以愉快地在德语和东欧键盘和代码页之间切换(即使在 Windows 2000 中)。
    【解决方案2】:

    Open XML 库中有编码工具。有cUnicodeCodecsWin32 单元,其功能如下:EncodingToUTF16()

    我在 ISO Latin2 和 UTF-8 之间转换的代码如下所示:

      s2 := EncodingToUTF16('ISO-8859-2', s);
      s2utf8 := UTF16ToEncoding('UTF-8', s2);
    

    【讨论】:

    • 请注意,较新版本的 Delphi 包含 OpenXML 作为可选 XML 库。
    【解决方案3】:

    您问题中的 Python 代码返回一个 UTF-8 编码的字符串。要使用 2009 之前的 Delphi 版本执行此操作,您可以使用类似于以下内容的代码:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Src, Dest: string;
      Len: integer;
      buf : array[0..2048] of WideChar;
    begin
      Src := Edit1.Text;
      Len := MultiByteToWideChar(CP_ACP, 0, PChar(Src), Length(Src), @buf[0], 2048);
      buf[Len] := #0;
      SetLength(Dest, 2048);
      SetLength(Dest, WideCharToMultiByte(CP_UTF8, 0, @buf[0], Len, PChar(Dest),
        2048, nil, nil));
      Edit2.Text := Dest;
    end;
    

    请注意,这不会更改当前线程区域设置,它只是将正确的代码页参数传递给 API。

    【讨论】:

    • 对于具有 UTF8Encode 的 Delphi 版本,或者只是 UTF8Encode(WideString(Edit1.Text))
    • 当然。然而,这个答案是为了接近问题中的代码,希望能说明问题出在哪里。
    • 这个简单的例子(转换为 WideString)不好,因为我们使用 iso-8859-2 数据,但是我们使用的机器是英文的,所以我们失去了口音...... :-(
    • 我忘了写的是:Delphi 6 Professional。
    • @durumdara:是的,答案中的代码适用于任何源编码,只需将正确的代码页参数传递给MultiByteToWideChar()CP_ACP 用于当前系统代码页,这是 VCL 转换将始终使用的。
    【解决方案4】:

    Windows 将代码页 28592 用于 ISO-8859-2。如果您有一个包含 ISO-8859-2 编码字节的缓冲区,那么您必须先将字节解码为 UTF-16,然后将结果编码为 UTF-8。根据您使用的 Delphi 版本,您可以:

    1) 在 D2009 之前,使用 MultiByteToWideChar() 和 WideCharToMultiByte():

    function EncodeToUTF(const inputstr: AnsiString): UTF8String;
    var
      ret: Integer;
      uns: WideString;
    begin
      Result := '';
      if inputstr = '' then Exit;
      ret := MultiByteToWideChar(28592, 0, PAnsiChar(inputstr), Length(inputstr), nil, 0);
      if ret < 1 then Exit;
      SetLength(uns, ret);
      MultiByteToWideChar(28592, 0, PAnsiChar(inputstr), Length(inputstr), PWideChar(uns), Length(uns));
      ret := WideCharToMultiByte(65001, 0, PWideChar(uns), Length(uns), nil, 0, nil, nil);
      if ret < 1 then Exit;
      SetLength(Result, ret);
      WideCharToMultiByte(65001, 0, PWideChar(uns), Length(uns), PAnsiChar(Result), Length(Result), nil, nil);
    end;
    

    2a) 在 D2009+ 上,使用 SysUtils.TEncoding.Convert():

    function EncodeToUTF(const inputstr: RawByteString): UTF8String;
    var
      enc: TEncoding;
      buf: TBytes;
    begin
      Result := '';
      if inputstr = '' then Exit;
      enc := TEncoding.GetEncoding(28592);
      try
        buf := TEncoding.Convert(enc, TEncoding.UTF8, BytesOf(inputstr));
        if Length(buf) > 0 then
          SetString(Result, PAnsiChar(@buf[0]), Length(buf));
      finally
        enc.Free;
      end;
    end;
    

    2b) 在 D2009+ 上,或者定义一个新的字符串 typedef,将数据放入其中,并将其分配给 UTF8String 变量。无需手动编码/解码,RTL 将为您处理一切:

    type
      Latin2String = type AnsiString(28592);
    
    var
      inputstr: Latin2String;
      outputstr: UTF8String;
    begin
      // put the ISO-8859-2 encoded bytes into inputstr, then...
      outputstr := inputstr;
    end;
    

    【讨论】:

    • -1 EncodeToUTF 无法为 Delphi2009 编译,修复后会更改我的投票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    相关资源
    最近更新 更多