我的问题是关于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转换为字符串。
答案 0 :(得分:6)
ThisStr
是UTF8String
,您的其他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>
上下文和字符编码很重要!