5

我想像 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 结果(相同的字符串),并且口音相同,我不会丢失不是英语语言的 ŐŰ。

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

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

4

4 回答 4

7

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;
于 2010-09-07T20:01:34.043 回答
0

如果您使用的是 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

于 2010-09-07T12:01:43.503 回答
0

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

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

  s2 := EncodingToUTF16('ISO-8859-2', s);
  s2utf8 := UTF16ToEncoding('UTF-8', s2);
于 2010-09-07T12:05:04.400 回答
0

您问题中的 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。

于 2010-09-07T12:24:16.313 回答