Delphi 2009中的RawByteString奇怪行为解析

5
假设由于某种扭曲的原因,您想要显示UTF8String的原始字节内容。
var
  utf8Str : UTF8String;
begin    
  utf8Str := '€ąćęłńóśźż';
end;

(1) 这不行,它显示可读形式:

memo1.Lines.Add( RawByteString( utf8Str ));
// output: '€ąćęłńóśźż'

(2) 然而,这里确实“有效” - 请注意连接操作:

memo1.Lines.Add( 'x' + RawByteString( utf8Str ));
// output: 'x€ąćęłńóśźż'

我理解(1),尽管编译器强制将RawByteString转换为UnicodeString可能会阻止原样显示变量。但是,为什么行为在(2)中发生了改变呢?

(3) 更奇怪的是 - 让我们反转拼接:

memo1.Lines.Add( RawByteString( utf8Str ) + 'x' ); 
// output: '€ąćęłńóśźżx'

我一直在研究Delphi中的新型字符串类型,觉得自己已经理解了它们的工作原理,但是这个问题令我感到困惑。

2个回答

9

RawByteString只是为了最小化需要使用各种不同代码页亲和性的AnsiString的函数的重载数量而存在。

通常情况下,不要声明RawByteString类型的变量。不要将值转换为该类型。不要对该类型的变量进行连接操作。你唯一能做的事情就是:

  • 声明此类型的参数(最初的意图)
  • 在此类参数上进行索引
  • 在此类参数中搜索
  • 智能操作,检查字符串的实际代码页,使用StringCodePage函数。

例如,你会注意到StringCodePage函数本身使用RawByteString作为其参数类型。这样,它将适用于任何AnsiString,而不是在将其作为参数传递之前进行代码页转换。

对于你的情况,像连接之类的操作在很大程度上是未定义的。行为在RTM和Update 2之间发生了变化,但当RTL字符串连接函数接收具有不同代码页的多个字符串时,它没有简单的方法来确定应该用于最终字符串的代码页。这只是为什么你不应该像这里一样连接它们的一个原因。


谢谢,巴里,这很有道理。连接只是一个“如果我按下这个按钮会发生什么”的实验,没有实际价值。不过看到Delphi引入这样的未定义行为还是很奇怪的 - 以前从来没有太多这样的情况。 - Marek Jedliński

1

你不能直接将字符串添加到TMemo中。在Delphi 2009中,TMemo只能处理Unicode编码的字符串,因此你需要进行某种形式的转换。

如果你想要假装你的UTF8String使用代码页1252,请按照以下步骤操作:

var
  utf8Str : UTF8String;
  Raw: RawByteString;
begin
  utf8Str := '€ąćęłńóśźż';
  Raw := utf8Str;
  SetCodePage(Raw, 1252, False);
  Memo.Lines.Add(Raw);
end;

更多细节请参见我的文章有效使用RawByteString


UTF-8是一种8位编码。它要求处理代码单元$00-$FF时按原样处理。但是,在转换为UTF-16时,代码页1252将代码单元$80-$9F映射到不同的值。因此,您应该使用代码页28591(ISO-8859-1)。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接