使用选项测试StrUtils.SearchBuf时[soWholeWord,soDown]
,会发生一些意外结果.
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.
Run Code Online (Sandbox Code Playgroud)
为什么' 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.
Run Code Online (Sandbox Code Playgroud)
我根本没有任何意义.除了功能有缺陷.
XE7,XE6和XE中的结果相同.
更新
对我来说这看起来像个错误.这是搜索的代码:
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;
Run Code Online (Sandbox Code Playgroud)
每次while
循环,我们检查soWholeWord
选项中是否有,然后前进到下一个单词的开头.但是我们只会这样做
Result <> @Buf[SelStart]
Run Code Online (Sandbox Code Playgroud)
现在,Result
是当前指针进入缓冲区,匹配的候选者.因此,此测试检查我们是否处于搜索字符串的开头.
此测试的含义是,如果搜索的字符串以非字母数字文本开头,则我们无法超越非字母数字文本到第一个单词的开头.
现在,您可能决定删除测试
Result <> @Buf[SelStart]
Run Code Online (Sandbox Code Playgroud)
但是,如果你这样做,你会发现如果它位于字符串的开头,你就不再匹配该单词.所以你只会以不同的方式失败.处理这个问题的正确方法是确保FindNextWordStart
如果我们在字符串的开头处不会前进,并且文本中有字母数字.
我的猜测是原作者编写了这样的代码:
if (soWholeWord in Options) then
if not FindNextWordStart(Result) then Break;
Run Code Online (Sandbox Code Playgroud)
然后他们发现字符串开头的单词不匹配,并将代码更改为:
if (soWholeWord in Options) and (Result <> @Buf[SelStart]) then
if not FindNextWordStart(Result) then Break;
Run Code Online (Sandbox Code Playgroud)
如果字符串以非字母数字文本开头,则没有人测试发生了什么.
这样的事情似乎完成了工作:
if (soWholeWord in Options) then
if (Result <> @Buf[SelStart]) or not Result^.IsLetterOrDigit then
if not FindNextWordStart(Result) then Break;
Run Code Online (Sandbox Code Playgroud)