Delphi:如何恢复双重编码的UTF8文本

时间:2017-08-25 14:05:00

标签: delphi

$C3 $A2 $C2 $80 $C2 $99$E2 $80 $99的双重编码UTF-8格式,它是Unicode 字符的UTF-8编码格式。

$E2被处理为单字节字符,并且被UTF-8编码为$C3 $A2$80被重新编码为$C2 $80$99被重新编码为$C2 $99

我怎样才能以比使用它更聪明的方式取回$E2 $80 $99

ThisText := AnsiReplaceStr(ThisText, #$C3#$A2#$C2#$80#$C2#$99, '’');

对于所有角色?

这是一个不需要的双UTF8编码的常见问题。 解决方案(?)是在线提供的,但仅限于Python,PHP或SQL。

这样的事情:

CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8)

哪个恕我直言在这里工作,因为$C2 $80$C2 $99都不是CP1252的字符。 ANSI中的转换为$E2 $3F $3F而不是所需的$E2 $ 80 $99

1 个答案:

答案 0 :(得分:6)

如果您知道数据是双重编码的,那么只需对其进行双重解码即可。在UTF-8中对其进行一次解码,然后将结果值截断为8位,并在UTF-8中再次对其进行解码。

$C3 $A2 -> $00E2 -> $E2
$C2 $80 -> $0080 -> $80
$C2 $99 -> $0099 -> $99

$E2 $80 $99 -> ’

例如

function FixUTF8(const S: UTF8String): UTF8String;
var
  Temp: UnicodeString; // use WideString prior to D2009
  I: Integer;
begin
  // use UTF8Decode() prior to D2009
  Temp := UnicodeString(S); // UTF-8 -> UTF-16
  SetLength(Result, Length(Temp));
  for I := 1 to Length(Temp) do
    Result[I] := AnsiChar(Ord(Temp[I])); // truncate to 8bit
end;

然而,实际上,数据不仅仅是双UTF-8编码。它首先是UTF-8编码,然后被误解为Latin-1并再次以UTF-8编码,因此您还必须考虑额外的Latin-1步骤:

function FixUTF8(const S: UTF8String): UTF8String;
type
  Latin1String = type AnsiString(28591); // or 1252
var
  Temp: RawByteString;
begin
  // use UTF8Decode() and WideCharToMultiByte() prior to D2009
  Temp := Latin1String(S); // UTF-8 -> UTF-16 -> Latin-1
  SetCodePage(Temp, CP_UTF8, False); // don't re-encode, just re-interpret
  Result := Temp; //return as-is
end;

无论哪种方式,现在都可以这样做:

var
  ThisText: UTF8String;
begin
  ThisText := #$C3#$A2#$C2#$80#$C2#$99;
  ThisText := FixUTF8(ThisText);
  ... 
end;

然而,真正的解决方案是首先避免错误的双重编码。