在Delphi Alexandria RTL中,它们具有以下功能:
function ScanChar(const S: string; var Pos: Integer; Ch: Char): Boolean;
var
C: Char;
begin
if (Ch = ' ') and ScanBlanks(S, Pos) then
Exit(True);
Result := False;
if Pos <= High(S) then
begin
C := S[Pos];
if C = Ch then
Result := True
else if (Ch >= 'a') and (Ch <= 'z') and (C >= 'a') and (C <= 'z') then
Result := Char(Word(C) xor B1a0a1b20) = Char(Word(Ch) xor B1a0a1b20)
else if Ch.IsLetter and C.IsLetter then
Result := ToUpper(C) = ToUpper(Ch);
if Result then
Inc(Pos);
end;
end;
我不能理解这种比较的目的:
else if (Ch >= 'a') and (Ch <= 'z') and (C >= 'a') and (C <= 'z') then
Result := Char(Word(C) xor B1a1a1b20) = Char(Word(Ch) xor B1a1a1b20)
看起来和这样做是一样的:
else if (Ch >= 'a') and (Ch <= 'z') and (C >= 'a') and (C <= 'z') then
Result := c = Ch
这是真的吗?
2条答案
按热度按时间yhived7q1#
ELSE IF(CH>=‘a’)AND(CH<=‘z’)AND(C>=‘a’)AND(C<=‘z’)则结果:=CHAR(WORD(C)XOR$0020)=CHAR(WORD(CH)XOR$0020)
此比较的目的是在字符是纯ASCII字母的情况下进行优化和更快的比较,并避免通过可以处理Unicode字符的
ToUpper
函数调用昂贵的WinAPI。或者,如果这种比较本身不会被严重打破,至少这是会发生的事情。
比较检查这两个字符是否都是小写,并且落在小写字母
a
(ASCII值97)和小写字母z
(ASCII值122)之间。但它实际上应该检查的是,这两个字符是否都在大写字母A
(ASCII值65)和小写字母z
之间,覆盖了ASCII字母的整个范围,而不考虑它们的大小写。(该范围内的非字母字符很少,但这些字符并不相关,因为Result
赋值永远不会为这些字符中的任何一个生成True
。)修复后,我们还需要修复
Result
赋值表达式,因为它不能正确比较小写和大写字母。要做到这一点,我们只需对所有字符使用or
运算符,它会将大写字符转换为小写,并保持小写不变。如前所述,在代码中的这一点上,可以安全地忽略该范围内的非字母字符。ScanChar
函数的该部分的正确代码为:注意:即使原始的
ScanChar
函数包含错误的代码,该函数的结果仍然是正确的,因为对于相同的字母,在不同的情况下,代码将始终通过IF分支的ToUpper
部分。vhmi4jdf2#
它与
C = Ch
不完全相同,但我想结果是相同的。这种比较是多余的,IMHO。它使用
XOR
将小写ASCII字母转换为大写ASCII字母(因为它们只相差1位),然后比较大写字母是否相等。但是下面使用IsLetter
+ToUpper
进行的比较做了同样的事情,只是针对任何字母,而不仅仅是ASCII字母。