delphi – 将UnicodeString转换为AnsiString

前端之家收集整理的这篇文章主要介绍了delphi – 将UnicodeString转换为AnsiString前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在旧的时代,我有一个函数可以将WideString转换为指定代码页的AnsiString:
function WideStringToString(const Source: WideString; CodePage: UINT): AnsiString;
...
begin
   ...
    // Convert source UTF-16 string (WideString) to the destination using the code-page
    strLen := WideCharToMultiByte(CodePage,PWideChar(Source),Length(Source),//Source
        PAnsiChar(cpStr),strLen,//Destination
        nil,nil);
    ...
end;

一切都奏效我通过函数unicode字符串(即UTF-16编码数据)并将其转换为AnsiString,但应了解,AnsiString中的字节表示来自指定代码页的字符。

例如:

TUnicodeHelper.WideStringToString('Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ',1252);

将返回Windows-1252编码的字符串:

The qùíçk brown fôx jumped ovêr the lázÿ dog

Note: Information was of course lost during the conversion from the full Unicode character set to the limited confines of the Windows-1252 code page:

  • Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ (before)
  • The qùíçk brown fôx jumped ovêr the lázÿ dog (after)

但是Windows WideChartoMultiByte在最佳匹配映射方面做得相当不错;因为它是设计来做的。

现在后来的时候

现在我们在后来的时候。 WideString现在是一个耻辱,UnicodeString是善良。这是一个无关紧要的变化因为Windows函数只需要一个指向一系列WideChar的指针(UnicodeString也是这样)。所以我们更改声明来使用UnicodeString:

funtion WideStringToString(const Source: UnicodeString; CodePage: UINT): AnsiString;
begin
   ...
end;

现在我们来到返回值。我有一个包含字节的AnsiString:

54 68 65 20 71 F9 ED E7  The qùíç
6B 20 62 72 6F 77 6E 20  k brown 
66 F4 78 20 6A 75 6D 70  fôx jump
65 64 20 6F 76 EA 72 20  ed ovêr 
74 68 65 20 6C E1 7A FF  the lázÿ
20 64 6F 67               dog

在古老的时代,这是罚款。我跟踪了AnsiString实际包含的代码页;我不得不记住,返回的AnsiString没有使用计算机的区域设置编码(例如Windows 1258),而是使用另一个代码页(CodePage代码页)进行编码。

但是在Delphi XE6中,AnsiString也秘密地包含了代码页:

> codePage:1258
长度:44
>值:qùíçk棕色fôx跳过了ÿ狗

代码错误。 Delphi正在指定我的电脑的代码页,而不是字符串的代码页。从技术上讲,这不是一个问题,我总是明白,AnsiString在一个特定的代码页,我只需要一定要传递这些信息。

所以当我想解码字符串时,我必须传递代码页:

s := TUnicodeHeper.StringToWideString(s,1252);

function StringToWideString(s: AnsiString; CodePage: UINT): UnicodeString;
begin
   ...
   MultiByteToWideChar(...);
   ...
end;

然后一个人把所有东西都拧上来

问题是在旧的时候我宣布一个类型称为Utf8String:

type
   Utf8String = type AnsiString;

因为这是很普遍的:

function TUnicodeHelper.WideStringToUtf8(const s: UnicodeString): Utf8String;
begin
   Result := WideStringToString(s,CP_UTF8);
end;

反之亦然:

function TUnicodeHelper.Utf8ToWideString(const s: Utf8String): UnicodeString;
begin
   Result := StringToWideString(s,CP_UTF8);
end;

现在在XE6我有一个功能,需要一个Utf8String。如果某些现有的代码采用UTF-8编码的AnsiString,并尝试使用Utf8ToWideString将其转换为UnicodeString,那么它将失败:

s: AnsiString;
s := UnicodeStringToString('Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ',CP_UTF8);

...

 ws: UnicodeString;
 ws := Utf8ToWideString(s); //Delphi will treat s an CP1252,and convert it to UTF8

或者更糟的是,现有代码的广度是:

s: Utf8String;
s := UnicodeStringToString('Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ',CP_UTF8);

返回的字符串将变得完全失效:

>函数返回AnsiString(1252)(AnsiString标记为使用当前代码页进行编码)
>返回结果存储在AnsiString(65001)字符串(Utf8String)
> Delphi将UTF-8编码的字符串转换为UTF-8,就好像是1252一样。

如何向前迈进

理想情况下,我的UnicodeStringToString(string,codePage)函数(返回一个AnsiString)可以将CodePage内的字符串设置为使用类似于SetCodePage的实际代码页:

function UnicodeStringToString(s: UnicodeString; CodePage: UINT): AnsiString;
begin
   ...
   WideCharToMultiByte(...);
   ...

   //Adjust the codepage contained in the AnsiString to match reality
   //SetCodePage(Result,CodePage,False); SetCodePage only works on RawByteString
   if Length(Result) > 0 then
      PStrRec(PByte(Result) - SizeOf(StrRec)).codePage := CodePage;
end;

除了用AnsiString的内部结构手动捣碎是非常危险的。

那么返回RawByteString呢?

有人说过,由很多不是我的人,RawByteString意在成为普遍接受者;它不是作为一个返回参数:

function UnicodeStringToString(s: UnicodeString; CodePage: UINT): RawByteString;
begin
   ...
   WideCharToMultiByte(...);
   ...

   //Adjust the codepage contained in the AnsiString to match reality
   SetCodePage(Result,False); SetCodePage only works on RawByteString
end;

这具有能够使用支持和记录的SetCodePage的优点。

但是如果我们要跨越一行,并且开始返回RawByteString,那么Delphi肯定有一个可以将UnicodeString转换为RawByteString字符串的功能,反之亦然:

function WideStringToString(const s: UnicodeString; CodePage: UINT): RawByteString;
begin
   Result := SysUtils.Something(s,CodePage);
end;

function StringToWideString(const s: RawByteString; CodePage: UINT): UnicodeString;
begin
   Result := SysUtils.SomethingElse(s,CodePage);       
end;

但是是什么呢

还是我该怎么办?

这是一个琐碎的问题的长期背景。真正的问题当然是我该怎么办?那里有很多代码取决于UnicodeStringToString,反之亦然。

TL;博士:

我可以通过执行以下操作将UnicodeString转换为UTF:

Utf8Encode('Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ');

我可以通过使用以下方式将UnicodeString转换为当前的代码页:

AnsiString('Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ');

但是如何将UnicodeString转换为任意(未指定)的代码页?

我的感觉是,因为一切真的是一个AnsiString:

Utf8String = AnsiString(65001);
RawByteString = AnsiString(65535);

我应该咬住子弹,打开AnsiString结构,并将正确的代码页戳入它:

function StringToAnsi(const s: UnicodeString; CodePage: UINT): AnsiString;
begin
   LocaleCharsFromUnicode(CodePage,...,s,...);

   ...

   if Length(Result) > 0 then
      PStrRec(PByte(Result) - SizeOf(StrRec)).codePage := CodePage;
end;

然后,VCL的其余部分将落在一起。

解决方法

在这种特殊情况下,使用RawByteString是一个适当的解决方案:
function WideStringToString(const Source: UnicodeString; CodePage: UINT): RawByteString;
var
  strLen: Integer;
begin
  strLen := LocaleCharsFromUnicode(CodePage,nil,nil));
  if strLen > 0 then
  begin
    SetLength(Result,strLen);
    LocaleCharsFromUnicode(CodePage,PAnsiChar(Result),nil));
    SetCodePage(Result,False);
  end;
end;

这样,RawByteString保存代码页,并将RawByteString分配给任何其他字符串类型,无论是AnsiString还是UTF8String或其他任何内容,都将允许RTL自动将RawByteString数据从当前代码页转换为目标字符串的代码页(包括转换为UnicodeString)。

如果你绝对必须返回一个AnsiString(我不推荐),你仍然可以通过类型转换使用SetCodePage():

function WideStringToString(const Source: UnicodeString; CodePage: UINT): AnsiString;
var
  strLen: Integer;
begin
  strLen := LocaleCharsFromUnicode(CodePage,nil));
    SetCodePage(PRawByteString(@Result)^,False);
  end;
end;

反之则比较简单,只需使用已经存储在(Ansi | RawByte)String中的代码页(只需确保这些代码总是准确的),因为RTL已经知道如何检索和使用代码页:

function StringToWideString(const Source: AnsiString): UnicodeString;
begin
  Result := UnicodeString(Source);
end;
function StringToWideString(const Source: RawByteString): UnicodeString;
begin
  Result := UnicodeString(Source);
end;

话虽如此,我建议完全删除帮助函数,而只是使用类型的字符串。让RTL为您处理转换:

type
  Win1252String = type AnsiString(1252);

var
  s: UnicodeString;
  a: Win1252String;
begin
  s := 'Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ';
  a := Win1252String(s);
  s := UnicodeString(a);
end;
var
  s: UnicodeString;
  u: UTF8String;
begin
  s := 'Ŧĥε qùíçķ ƀřǭŵņ fôx ǰűmpεď ōvêŗ ţħě łáƶÿ ďơǥ';
  u := UTF8String(s);
  s := UnicodeString(u);
end;
原文链接:https://www.f2er.com/delphi/103404.html

猜你在找的Delphi相关文章