Delphi 2010 system.pos搜索utf8string

时间:2017-08-04 09:22:35

标签: delphi

我的问题是关于delphi 2010 system.pos

我想了解原因:

const
ThisStr : UTF8String = 'abcā—46°40’こ';  // — is #$E28094,  ’ is #$E28099

i := Pos('°', ThisStr);   // not found (i = 12 instead of 8)
i := Pos('—', ThisStr);   // i = 0 instead of 5
i := Pos('’', ThisStr);   // i = 0 instead of 11

如果我将char转换为字符串,则所有答案都是正确的。

i := Pos(string('—'), ThisStr) // i = 5

NB1:

i := Pos('こ', ThisStr); // i = 12
i := Pos('ā', ThisStr); // i = 4

给出正确的答案,不需要从char转换为字符串。

NB2: sysutils.ansipos,strutils.ansipos,strutils.posex
在所有情况下给出正确答案,不需要将char转换为字符串。

1 个答案:

答案 0 :(得分:6)

ThisStrUTF8String,您的其他System.Pos()输入是无类型文字。这是一个需要注意的重要事实,因为它会影响编译器调用System.Pos()的方式。

在D2010中,System单位有三次重载System.Pos()

function Pos(const substr, str: UnicodeString): Integer; overload;
function Pos(const substr, str: RawByteString): Integer; overload;
function Pos(const substr, str: WideString): Integer; overload;

在没有任何转换的情况下调用System.Pos()时,您的输入最接近RawByteString重载,因为它是唯一不需要对输入值进行任何运行时转换的重载。

无类型文字的编译字符编码基于它使用的上下文。文字'abcā—46°40’こ'被分配给UTF8String,因此在编译时它是UTF-8编码的。 UTF8String可以按原样传递给RawByteString,这意味着您的其他文字被分配给RawByteString,因此它们将由编译器以ANSI编码,而不是UTF- 8。

您的UTF-8字符串中包含12个Unicode字符。以UTF-8编码时,它有20个AnsiChar元素:

a = $61
b = $62
c = $63
ā = $C4 $81
— = $E2 $80 $94
4 = $34
6 = $36
° = $C2 $B0
4 = $34
0 = $30
’ = $E2 $80 $99
こ = $E3 $81 $93 

另一方面,当用ANSI编码时,字符文字将只有1 AnsiChar(它们的值将取决于系统的默认语言环境,因此您的结果可能与我的不同):

° = $B0 
— = $97 
’ = $92
こ = $3F (unless your system locale supports this character! mine doesn't)
ā = $61

即使您将源文件编码更改为UTF-8,字符文字仍将以ANSI编码,而不是UTF-8。

所以:

  • Pos('°', ThisStr)正在搜索$B0,可在元素12
  • 找到
  • Pos('—', ThisStr)正在搜索找不到的$97
  • Pos('’', ThisStr)正在搜索找不到的$92
  • Pos('こ', ThisStr)正在搜索找不到的$3F
  • Pos('ā', ThisStr)正在搜索$61,可在元素1
  • 找到

搜索到的字符与UTF8String不匹配,这就是为什么找不到它们的原因。

通过将System.Pos()的第一个参数强制转换为string,您强制编译器使用UnicodeString重载而不是RawByteString重载。因此,UTF8String将在运行时转换为UnicodeString,并且字符文字被分配给UnicodeString,因此它们将在编译时以UTF-16编码。

转换后的UTF8String - > UnicodeString将包含12个WideChar元素:

a = $0061
b = $0062
c = $0063
ā = $0101
— = $2014
4 = $0034
6 = $0036
° = $00B0
4 = $0034
0 = $0030
’ = $2019
こ = $3053

当你的字符文字以UTF-16编码时,它们各有1 WideChar

° = $00B0
— = $2014
’ = $2019
こ = $3053 
ā = $0101 

所以:

  • Pos(string('°'), string(ThisStr))正在搜索$00B0,可在元素8
  • 找到
  • Pos(string('—'), string(ThisStr))正在搜索$2014,可在元素5
  • 找到
  • Pos(string('’'), string(ThisStr))正在搜索$2019,可在元素11
  • 找到
  • Pos(string('こ'), string(ThisStr))正在搜索$3053,可在元素12
  • 找到
  • Pos(string('ā'), string(ThisStr))正在搜索$0101,可在元素4
  • 找到

搜索到的字符与转换后的UTF8String - > UnicodeString字符串相匹配,这就是为什么找到它们的原因。

SysUtils.AnsiPos()StrUtils.PosEx()没有重载,他们只接受UnicodeString作为输入,因此它们与调用UnicodeString System.Pos()重载的结果相同。如果您在AnsiStrings子句中加入uses单位,则会为AnsiPos()添加AnsiString的重叠,这会给您与上述结果截然不同的结果。< / p>

上下文和字符编码很重要!