在Delphi Alexandria RTL中,ScanChar()编写得很糟糕吗?

vptzau2j  于 2022-09-21  发布在  其他
关注(0)|答案(2)|浏览(167)

在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

这是真的吗?

yhived7q

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函数的该部分的正确代码为:

...
else
if (Ch >= 'A') and (Ch <= 'z') and (C >= 'A') and (C <= 'z') then
  Result := Word(Ch) or B1a0a1b20 = Word(C) or B1a0a1b20
else
...

注意:即使原始的ScanChar函数包含错误的代码,该函数的结果仍然是正确的,因为对于相同的字母,在不同的情况下,代码将始终通过IF分支的ToUpper部分。

vhmi4jdf

vhmi4jdf2#

它与C = Ch不完全相同,但我想结果是相同的。

这种比较是多余的,IMHO。它使用XOR将小写ASCII字母转换为大写ASCII字母(因为它们只相差1位),然后比较大写字母是否相等。但是下面使用IsLetter+ToUpper进行的比较做了同样的事情,只是针对任何字母,而不仅仅是ASCII字母。

相关问题