代码之家  ›  专栏  ›  技术社区  ›  Mick

在unicodestring中存储utf-8字符串

  •  9
  • Mick  · 技术社区  · 16 年前

    在Delphi2007中,您可以将UTF-8字符串存储在一个宽字符串中,然后将其传递给一个win32函数,例如。

    var
      UnicodeStr: WideString;
      UTF8Str: WideString;
    begin
      UnicodeStr:='some unicode text';
      UTF8Str:=UTF8Encode(UnicodeStr);
      Windows.SomeFunction(PWideChar(UTF8Str), ...)
    end;
    

    Delphi2007不干扰utf8str的内容,也就是说,它被保留为存储在宽字符串中的UTF-8编码字符串。

    但在Delphi2010中,我正在努力寻找一种方法来做同样的事情,即在不从UTF-8自动转换的情况下,将一个UTF-8编码的字符串存储在一个宽字符串中。我无法传递指向utf-8字符串(或rawbytestring)的指针,例如,以下操作显然不起作用:

    var
      UnicodeStr: WideString;
      UTF8Str: UTF8String;
    begin
      UnicodeStr:='some unicode text';
      UTF8Str:=UTF8Encode(UnicodeStr);
      Windows.SomeFunction(PWideChar(UTF8Str), ...)
    end;
    
    3 回复  |  直到 10 年前
        1
  •  13
  •   Zoë Peterson RRUZ    16 年前

    最初的Delphi2007代码使用ANSI代码页将UTF-8字符串转换为宽字符串。要在Delphi2010中执行相同的操作,应该使用带有转换参数false的setcodepage。

    var
      UnicodeStr: UnicodeString;
      UTF8Str: RawByteString;
    begin
      UTF8Str := UTF8Encode('some unicode text');
      SetCodePage(UTF8Str, 0, False);
      UnicodeStr := UTF8Str;
      Windows.SomeFunction(PWideChar(UnicodeStr), ...)
    
        2
  •  3
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    嗯,你为什么这么做?为什么要将widestring编码为utf-8,以便再次将其存储回widestring。显然,您使用的是windows api的unicode版本。所以不需要使用utf-8编码的字符串。或者是我遗漏了什么。

    因为windows api函数要么是unicode(两个字节)要么是ansi(一个字节)。这里选择utf-8是错误的,因为它主要包含每个字符一个字节,但是对于ascii基以上的字符,它使用两个或更多字节。

    否则,Unicode Delphi中旧代码的等效项为:

    var
      UnicodeStr: string;
      UTF8Str: string;
    begin
      UnicodeStr:='some unicode text';
      UTF8Str:=UTF8Encode(UnicodeStr);
      Windows.SomeFunction(PWideChar(UTF8Str), ...)
    end;
    

    widestring和string(unicodestring)类似,但是新的unicodestring更快,因为它是引用计数的,而widestring不是。

    您的代码不正确,因为utf-8字符串中每个字符的字节数是可变的。”a“存储为一个字节。只是一个ascii字节码。另一方面,存储为两个字节。而且因为您使用的是pwidechar,所以函数总是要求每个字符有两个字节。

    还有另一个区别。在旧的delphi版本(ansi)中,utf8string只是一个ansistring。在Unicode版本的Delphi中,utf8string是一个字符串,后面有一个UTF-8代码页。所以它的行为不同。

    旧代码仍然可以正常工作:

    var
      UnicodeStr: WideString;
      UTF8Str: WideString;
    begin
      UnicodeStr:='some unicode text';
      UTF8Str:=UTF8Encode(UnicodeStr);
      Windows.SomeFunction(PWideChar(UTF8Str), ...)
    end;
    

    它将采取与德尔福2007年相同的行动。所以也许你在别的地方有问题。

    米克你是对的。编译器在幕后做一些额外的工作。为了避免这种情况,你可以这样做:

    var
      UTF8Str: AnsiString;
      UnicodeStr: WideString;
      TempString: RawByteString;
      ResultString: WideString;
    begin
      UnicodeStr := 'some unicode text';
      TempString := UTF8Encode(UnicodeStr);
      SetLength(UTF8Str, Length(TempString));
      Move(TempString[1], UTF8Str[1], Length(UTF8Str));
      ResultString := UTF8Str;
    end;
    

    我查过了,结果还是一样。因为我直接在内存中移动字节,所以没有在后台进行代码页转换。我相信这可以用更大的元素来完成,但关键是我认为这是你想要实现的方式。

        3
  •  0
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    哪个windows api调用希望传递utf-8字符串?它可以是ansi字符串,也可以是widestring(a或w函数)。widestring每个字符有两个字节,utf-8字符串有一个字节(如果超过前128个ascii字符,则有一个或多个字节)。

    把utf-8放在一个宽大的管柱里是没有意义的。当有一个windows函数需要一个指向utf-8字符串的指针时,您可能需要强制转换为pansichar。

    推荐文章