$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
。
答案 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;
然而,真正的解决方案是首先避免错误的双重编码。