当使用[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
最佳答案
对我来说,这似乎是个 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;