在 Unicode 感知 Delphi 版本中处理 AnsiString 及其十六进制代码

Handling AnsiString and its Hex code in Unicode aware Delphi versions

我是 运行 一个遗留应用程序,构建于 Delphi2007 年,过去我们通过在数据库中存储字符的 2 字节十六进制代码来处理非英语字符。 在阅读时,我们应用 char() 将这些十六进制代码转换为字符串。

字符串转十六进制(保存到数据库之前):

strHex := Format( '%x', [ Byte( strText[ lIndex ] ) shr 4 ] );
DataStr[ lPos ] := strHex[ 1 ];
inc( lPos );

strHex := Format( '%x', [ Byte( strText[ lIndex ] ) and [=11=]F ] );
DataStr[ lPos ] := strHex[ 1 ];
inc( lPos );

//in simple I am saving the Hex code to pcData

十六进制到字符串(从数据库读取后):

strText := strText + Chr( StrToInt('$'+ DataStr[lPos] + DataStr[lPos + 1]))

此代码在移动到 Delphi XE7 后开始中断,其中 string 被视为 UniCode 字符串,我们明确必须将字符串转换为 AnsiString 类型。

正在将以下字符串转换为十六进制
ТуцЕфылАшдеук8311
在 Delphi 2007 年给出:
\D2\F3\F6\C5\F4\FB\EB\C0\F8\E4\E5\F3\EA8311
在 Delphi XE7 中给出:
ABB1522


我想知道修改此代码以便处理遗留数据的最佳方法。

根据评论,您只需将此数据解码为本机 Unicode string。这样做:

  1. 从数据库读取编码文本到string变量中。
  2. 将该文本解码为字节数组而不是字符串。您的 Delphi 2007 代码几乎可以直接使用,但它需要写入字节数组而不是字符串。
  3. 该字节数组采用 ANSI 1251 编码。用 TEncoding.GetString 解码它。您需要使用正确的代码页 Encoding := TEncoding.GetEncoding(1251).
  4. 创建 TEncoding class 的实例

首先,生成十六进制字符串的更简单方法是使用 RTL 自己的 BinToHex() 函数而不是编写自己的转换代码,例如:

var
  ...
  s: AnsiString;
  DataStr: string; 
  lPos: Integer;
  ...
begin
  ...
  s := '...';
  BinToHex(PAnsiChar(s), @DataStr[lPos], Length(s)); 
  Inc(lPos, Length(s)*2);
  ...
end;

然后,您可以使用HexToBin()来反转它。由于您正在处理编码的 ANSI 数据,您可以声明一个 AnsiString 变量,该变量对所需的代码页编码具有亲和力(在您的情况下,可能是 1251),将十六进制代码直接读入该变量,然后 assign/cast 到正常 String 并让 RTL 为您处理到 Unicode 的转换:

type
  Win1251String = type AnsiString(1251);
var
  ...
  tmp: Win1251String;
  DataStr, strText: string;
  lPos: Integer;
  ...
begin
  ...
  SetLength(tmp, LengthOfHex div 2);
  HexToBin(@DataStr[lPos], PAnsiChar(tmp), Length(tmp));
  strText := String(tmp);
  ...
end;