delphi SearchBuf soWholeWord意外输出

3xiyfsfu  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(142)

使用[soWholeWord,soDown]选项测试StrUtils.SearchBuf时,出现了一些意外结果。

program Project1;

Uses
  SysUtils,StrUtils;

function WordFound(aString,searchString: String): Boolean;
begin
  Result := SearchBuf(PChar(aString),Length(aString), 0, 0, searchString, 
    [soWholeWord,soDown]) <> nil;
end;

Procedure Test(aString,searchString: String);
begin
  WriteLn('"',searchString,'" in "',aString,'"',#9,' : ',
    WordFound(aString,searchString));
end;

begin
  Test('Delphi','Delphi');   // True
  Test('Delphi ','Delphi');  // True
  Test(' Delphi','Delphi');  // False
  Test(' Delphi ','Delphi'); // False
  ReadLn;
end.
    • 为什么不将' Delphi'' Delphi '视为一个完整的单词?**

反向搜索怎么样?

function WordFoundRev(aString,searchString: String): Boolean;
begin
  Result := SearchBuf(PChar(aString),Length(aString),Length(aString)-1,0,searchString, 
    [soWholeWord]) <> nil;
end;

Procedure TestRev(aString,searchString: String);
begin
  WriteLn('"',searchString,'" in "',aString,'"',#9,' : ',
    WordFoundRev(aString,searchString));
end;

begin
  TestRev('Delphi','Delphi');   // False
  TestRev('Delphi ','Delphi');  // True
  TestRev(' Delphi','Delphi');  // False
  TestRev(' Delphi ','Delphi'); // True
  ReadLn;
end.

我完全搞不懂这个。除了这个函数有缺陷。
XE7、XE6和XE的结果相同。

    • 更新**

QC127635 StrUtils.SearchBuf fails with [soWholeWord] option

hm2xizp9

hm2xizp91#

在我看来这是一个bug。下面是执行搜索的代码:

while SearchCount > 0 do
begin
  if (soWholeWord in Options) and (Result <> @Buf[SelStart]) then
    if not FindNextWordStart(Result) then Break;
  I := 0;
  while (CharMap[(Result[I])] = (SearchString[I+1])) do
  begin
    Inc(I);
    if I >= Length(SearchString) then
    begin
      if (not (soWholeWord in Options)) or
         (SearchCount = 0) or
         ((Byte(Result[I])) in WordDelimiters) then
        Exit;
      Break;
    end;
  end;
  Inc(Result, Direction);
  Dec(SearchCount);
end;

每次循环while时,我们都检查soWholeWord是否在选项中,然后前进到下一个单词的开头,但我们只在以下情况下才这样做

Result <> @Buf[SelStart]

现在,Result是当前指向缓冲区的指针,也就是匹配的候选项,所以这个测试检查我们是否在被搜索字符串的开头。
这个测试的意思是,如果搜索的字符串以非字母数字文本开始,我们就不能从非字母数字文本前进到第一个单词的开头。
现在,您可能决定删除以下测试

Result <> @Buf[SelStart]

但是如果你这样做的话,你会发现如果这个单词正好位于字符串的开头,你就不再匹配它了,所以你会以另一种方式失败,正确的处理方法是确保如果我们位于字符串的开头,并且那里的文本是字母数字,FindNextWordStart不会前进。
我猜原作者是这样写代码的:

if (soWholeWord in Options) then
  if not FindNextWordStart(Result) then Break;

然后他们发现字符串开头的单词不匹配,并将代码更改为:

if (soWholeWord in Options) and (Result <> @Buf[SelStart]) then
  if not FindNextWordStart(Result) then Break;

没有人测试过如果字符串以非字母数字文本开头会发生什么。
这样的事情似乎可以完成工作:

if (soWholeWord in Options) then
  if (Result <> @Buf[SelStart]) or not Result^.IsLetterOrDigit then
    if not FindNextWordStart(Result) then Break;

相关问题