使用 Base64 UTF-8 阿拉伯字符串时的 QR 读取问题

QR reading problem when using a Base64 UTF-8 Arabic string

我有一个标记的阿拉伯字符串,我想使用 Base64 编码对该字符串进行编码。在此字符串中使用英文字母时一切运行完美,但使用阿拉伯字母时,QR reader 未显示正确的字母。

这是我的代码:

function TForm1.GetMyString(TagNo: Integer; TagValue: string): string;
var
  Bytes, StrByte: TBytes;
  i: Integer;
begin
  SetLength(StrByte, Length(TagValue)+2);
  StrByte[0] := Byte(TagNo);
  StrByte[1] := Byte(Length(TagValue));
  for i := 2 to Length(StrByte)-1 do
    StrByte[i] := Byte(TagValue[i-1]);
  Result := TEncoding.UTF8.GetString(StrByte);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  s: String;
  Bytes: TBytes;
begin
  s := GetMyString(1, Edit1.Text) + GetMyString(2, Edit2.Text) +
              GetMyString(3, Edit3.Text) + GetMyString(4, Edit4.Text) +
              GetMyString(5, Edit5.Text);
  bytes := TEncoding.UTF8.GetBytes(s);
  QREdit.Text := TNetEncoding.Base64.EncodeBytesToString(Bytes);
end;

解码Base64字符串后,同样显示二维码读取结果 例如。 (E) 'D9E1'F) 而不是 (مؤسسة العمران)

我正在使用 ZXingQR 读取生成的字符串。

GetMyString()截断 一系列 UTF-16 字符到一个 8 位字节的数组中,以及将其他 非文本 字节到数组中,然后将整个数组视为 UTF-8(实际上不是)以生成新的 UTF-16 字符串。

然后 Button1Click() 正在获取那些顶起的 UTF-16 字符串,将它们连接在一起,并将结果转换为 UTF-8 以编码为 base64。

此方法仅适用于长度小于 128 个字符的 ASCII 字符串,以及值小于 128 的标记,因为 0..127 范围内的 ASCII 字节是 UTF-8 的子集。这不适用于超出此范围的非 ASCII characters/bytes。

您似乎想对一系列带标签的UTF-8 字符串进行base64 编码。如果是这样,那么尝试更像这样的东西:

procedure TForm1.GetMyString(TagNo: UInt8; const TagValue: string; Output: TStream);
var
  Bytes: TBytes;
begin
  Bytes := TEncoding.UTF8.GetBytes(TagValue);
  Assert(Length(Bytes) < 256);
  Output.WriteData(TagNo);
  Output.WriteData(UInt8(Length(Bytes)));
  Output.WriteData(Bytes, Length(Bytes));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Stream: TMemoryStream;
begin
  Stream := TMemoryStream.Create;
  try
    GetMyString(1, Edit1.Text, Stream);
    GetMyString(2, Edit2.Text, Stream);
    GetMyString(3, Edit3.Text, Stream);
    GetMyString(4, Edit4.Text, Stream);
    GetMyString(5, Edit5.Text, Stream);
    QREdit.Text := TNetEncoding.Base64.EncodeBytesToString(Stream.Memory, Stream.Size);
  finally
    Stream.Free;
  end;
end;

或者:

function TForm1.GetMyString(TagNo: UInt8; const TagValue: string): TBytes;
var
  Len: Integer;
begin
  Len := TEncoding.UTF8.GetByteCount(TagValue);
  Assert(Len < 256);
  SetLength(Result, 2+Len);
  Result[0] := Byte(TagNo);
  Result[1] := Byte(Len);
  TEncoding.UTF8.GetBytes(TagValue, 1, Length(TagValue), Result, 2);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Bytes: TBytes;
begin
  Bytes := Concat(
    GetMyString(1, Edit1.Text),
    GetMyString(2, Edit2.Text),
    GetMyString(3, Edit3.Text),
    GetMyString(4, Edit4.Text),
    GetMyString(5, Edit5.Text)
 );
 QREdit.Text := TNetEncoding.Base64.EncodeBytesToString(Bytes);
end;