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 作为输入,因此它们与调用System.Pos() 的UnicodeString 重载具有相同的结果。如果在uses 子句中包含AnsiStrings 单元,它会为AnsiString 添加AnsiPos() 的重载,这将得到与我上面描述的完全不同的结果。
上下文和字符编码很重要!