gpt4 book ai didi

delphi - 使用 UTF8String 转换非规范化字符

转载 作者:行者123 更新时间:2023-12-05 09:08:23 25 4
gpt4 key购买 nike

将以 UTF-8 编码的表情符号转换为字符串时,我们没有使用 UTF8ToString 获得正确的字符。我们从外部接口(interface)接收这些 UTF8 字符。我们使用在线 UTF8 解码器测试了 UTF 字符,发现它们包含正确的字符。我怀疑这些是复合字符。

procedure TestUTF8Convertion;
const
utf8Denormalized: RawByteString = #$ED#$A0#$BD#$ED#$B8#$85#$20 + #$ED#$A0#$BD#$ED#$B8#$86#$20 + #$ED#$A0#$BD#$ED#$B8#$8A;
utf8Normalized: RawByteString = #$F0#$9F#$98#$85 + #$F0#$9F#$98#$86 + #$F0#$9F#$98#$8A;
begin
Memo1.Lines.Add(UTF8ToString(utf8Denormalized));
Memo1.Lines.Add(UTF8ToString(utf8Normalized));
end;

Memo1 中的输出:

非规范化:���� ���� ����

归一化:😎😆😊

根据WinApi函数MultiByteToWideChar写自己的转换函数没有解决这个问题。

function UTF8DenormalizedToString(s: PAnsiChar): string;
var
pwc: PWideChar;
len: cardinal;
begin
GetMem(pwc, (Length(s) + 1) * SizeOf(WideChar));
len := MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, @s[0], -1, pwc, length(s));
SetString(result, pwc, len);
FreeMem(pwc);
end;

最佳答案

如果缓冲区中有 CESU-8 数据并且需要将其转换为 UTF-8,则可以将代理对替换为单个 UTF-8 编码字符。其余数据可以保持不变。

在这种情况下,您的表情符号是这样的:

  • 代码点:01 F6 05
  • UTF-8 : F0 9F 98 85
  • UTF-16 : D8 3D DE 05
  • CESU-8:ED A0 BD ED B8 85

CESU-8 中的高代理有这个数据:$003D

CESU-8 中的低代理有这个数据:$0205

正如 Remy 和 AmigoJack 所指出的,当您解码 Emoji 的 UTF-16 版本时,您会发现这些值。

在 UTF-16 的情况下,您还需要将 $003D 值乘以 $400 (shl 10),将结果添加到 $0205,然后将 $10000 添加到最终结果以获得代码点。

获得代码点后,您可以将其转换为一组 4 字节的 UTF-8 值。

function ValidHighSurrogate(const aBuffer: array of AnsiChar; i: integer): boolean;
var
n: byte;
begin
Result := False;
if (ord(aBuffer[i]) <> $ED) then
exit;

n := ord(aBuffer[i + 1]) shr 4;
if ((n and $A) <> $A) then
exit;

n := ord(aBuffer[i + 2]) shr 6;
if ((n and $2) = $2) then
Result := True;
end;

function ValidLowSurrogate(const aBuffer: array of AnsiChar; i: integer): boolean;
var
n: byte;
begin
Result := False;
if (ord(aBuffer[i]) <> $ED) then
exit;

n := ord(aBuffer[i + 1]) shr 4;
if ((n and $B) <> $B) then
exit;

n := ord(aBuffer[i + 2]) shr 6;
if ((n and $2) = $2) then
Result := True;
end;

function GetRawSurrogateValue(const aBuffer: array of AnsiChar; i: integer): integer;
var
a, b: integer;
begin
a := ord(aBuffer[i + 1]) and $0F;
b := ord(aBuffer[i + 2]) and $3F;

Result := (a shl 6) or b;
end;

function CESU8ToUTF8(const aBuffer: array of AnsiChar): boolean;
var
TempBuffer: array of AnsiChar;
i, j, TempLen: integer;
TempHigh, TempLow, TempCodePoint: integer;
begin
TempLen := length(aBuffer);
SetLength(TempBuffer, TempLen);

i := 0;
j := 0;
while (i < TempLen) do
if (i + 5 < TempLen) and ValidHighSurrogate(aBuffer, i) and
ValidLowSurrogate(aBuffer, i + 3) then
begin
TempHigh := GetRawSurrogateValue(aBuffer, i);
TempLow := GetRawSurrogateValue(aBuffer, i + 3);
TempCodePoint := (TempHigh shl 10) + TempLow + $10000;
TempBuffer[j] := AnsiChar($F0 + ((TempCodePoint and $1C0000) shr 18));
TempBuffer[j + 1] := AnsiChar($80 + ((TempCodePoint and $3F000) shr 12));
TempBuffer[j + 2] := AnsiChar($80 + ((TempCodePoint and $FC0) shr 6));
TempBuffer[j + 3] := AnsiChar($80 + (TempCodePoint and $3F));
inc(j, 4);
inc(i, 6);
end
else
begin
TempBuffer[j] := aBuffer[i];
inc(i);
inc(j);
end;

Result := < save the buffer here >;
end;

关于delphi - 使用 UTF8String 转换非规范化字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63574794/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com