有没有办法从字符串中获取 ANSI 字符?当字符串包含表情符号时 Utf8decode 失败

Is there a way to get just the ANSI characters from a string? Utf8decode fails when string contains emojis

首先,我从 HTTP 请求中获取了一个 TMemoryStream,其中包含响应的主体。 然后我将它加载到 TStringList 中并将文本保存在宽字符串中(也尝试使用 ansistring)。

问题是我需要转换字符串,因为用户语言是西班牙语,所以带重音符号的元音很常见,我需要存储信息。

lServerResponse := TStringList.Create;
lServerResponse.LoadFromStream(lResponseMemoryStream);

lStringResponse := lServerResponse.Text;
lDecodedResponse := Utf8Decode(lStringResponse );

如果响应(其中一部分)是“Hólá Múndó”,lStringResponse 值将为“Hólá Mãºndó”,lDecodedResponse 将为“Hólá Múndó”。

但是如果用户添加任何表情符号(如果表情符号是 ,lStringResponse 值将是“Hólá Múndó ðŸ∼€”)Utf8Decode 失败并且 returns 一个空字符串。 有没有办法只从字符串(或 MemoryStream)中获取 ANSI 字符?或者删除任何 Utf8Decode 无法转换的字符?

谢谢你的时间。

TMemoryStream 只是原始字节。没有理由将该流加载到 TStringList 中只是为了从中提取 (Wide|Ansi)String。您可以使用 SetString() 将字节直接分配给 AnsiString/UTF8String,例如:

var
  lStringResponse: UTF8String;
  lDecodedResponse: WideString;
begin
  SetString(lStringResponse, PAnsiChar(lResponseMemoryStream.Memory), lResponseMemoryStream.Size);
  lDecodedResponse := UTF8Decode(lStringResponse);
end;

只要确保 HTTP 内容确实编码为 UTF-8,否则此方法将不起作用。

也就是说 - Delphi 中的 UTF8Decode()(和 UTF8Encode())7 支持 U+FFFF 以上的 Unicode 代码点,这意味着他们根本不支持表情符号。该问题已在 Delphi 2009 年修复。

要在早期版本中解决该问题,您可以改用 Win32 API MultiByteToWideChar() 函数,例如:

uses
  ..., Windows;

function My_UTF8Decode(const S: UTF8String): WideString;
var
  WLen: Integer;
begin
  WLen := MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(S), Length(S), nil, 0);
  if WLen > 0 then
  begin
    SetLength(Result, WLen);
    MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(S), Length(S), PWideChar(Result), WLen);
  end else
    Result := '';
end;

var
  lStringResponse: UTF8String;
  lDecodedResponse: WideString;
begin
  SetString(lStringResponse, PAnsiChar(lResponseMemoryStream.Memory), lResponseMemoryStream.Size);
  lDecodedResponse := My_UTF8Decode(lStringResponse);
end;

或者:

uses
  ..., Windows;

function My_UTF8Decode(const S: PAnsiChar; const SLen: Integer): WideString;
var
  WLen: Integer;
begin
  WLen := MultiByteToWideChar(CP_UTF8, 0, S, SLen, nil, 0);
  if WLen > 0 then
  begin
    SetLength(Result, WLen);
    MultiByteToWideChar(CP_UTF8, 0, S, SLen, PWideChar(Result), WLen);
  end else
    Result := '';
end;

var
  lDecodedResponse: WideString;
begin
  lDecodedResponse := My_UTF8Decode(PAnsiChar(lResponseMemoryStream.Memory), lResponseMemoryStream.Size);
end;

或者,使用第 3 方 Unicode 转换库,例如 ICU or libiconv,它会为您处理此问题。