Delphi中是否有高效的全字匹配搜索功能?

7
在Delphi 2009或更高版本(Unicode)中,是否有任何内置函数或小型程序可以进行合理高效的全词搜索,您需要提供定义单词的分隔符,例如:
function ContainsWord(Word, Str: string): boolean;

const  { Delim holds the delimiters that are on either side of the word }
  Delim = ' .;,:(){}"/\<>!?[]'#$91#$92#$93#$94'-+*='#$A0#$84;

位置:

Word: string;  { is the Unicode string to search for }
Str: string;   { is the Unicode string to be searched }

我只需要返回一个布尔值,如果字符串中包含“Word”,则为true,否则为false。
肯定有相关的内容,因为标准的查找对话框有“仅匹配整个单词”作为其中一个选项。
通常(或最佳)如何实现?
结论:
RRUZ的答案非常完美。 SearchBuf例程正是我所需要的。 我甚至可以进入StrUtils例程,提取代码并修改以适应我的要求。
我惊讶地发现SearchBuf没有首先搜索单词,然后检查分隔符。 相反,它逐个字符地查看字符串中的字符以查找分隔符。 如果它找到一个分隔符,那么它会检查字符串和另一个分隔符。 如果没有找到它,则会查找另一个分隔符。 出于效率的考虑,这非常聪明!
4个回答

19
你可以使用带有 [soWholeWord] 选项的 SearchBuf 函数。
function SearchBuf(Buf: PAnsiChar; BufLen: Integer; SelStart: Integer; SelLength: Integer; SearchString: AnsiString; Options: TStringSearchOptions): PAnsiChar;

请参考这个示例

function ExistWordInString(aString:PWideChar;aSearchString:string;aSearchOptions: TStringSearchOptions): Boolean;
var
  Size : Integer;
Begin
      Size:=StrLen(aString);
      Result := SearchBuf(aString, Size, 0, 0, aSearchString, aSearchOptions)<>nil;
End;

按照以下方式使用

ExistWordInString('Go Delphi Go','Delphi',[soWholeWord,soDown]);

再见。


2
不错!你现在已经在自己的博客上发布了解决方案:http://theroadtodelphi.wordpress.com/2009/11/05,我在进一步研究时发现了它。感谢你在那里提供的额外信息。 - lkessler
ExistWordInString(' Delphi ','Delphi'[soWholeWord,soDown]); 失败。请参见SearchBuf soWholeWord意外输出 - LU RD

2
仅仅因为Delphi编辑器有一个“单词匹配”功能并不意味着Delphi库也提供它!通常,在大多数语言中,解决这个问题的方法是使用正则表达式。看起来它们(仍然)没有内置到Delphi中,因为有第三方库提供了相应的功能。我找到的第一个例子是:http://delphi.about.com/od/toppicks/tp/delphi-regular-expressions.htm。通常,您需要构建类似于以下内容的正则表达式:
myRegex = '[' + Delim + ']+' + Word + '[' + Delim + ']+';
if regexSearch (Str, myRegex) then ...

您需要从获取的库的文档中获取详细信息。我的示例没有正确处理单词从Str开头或结束,或是整个Str的情况。


1
如果您有以下类似的函数:

function ExistWordInString(aString:PWideChar;aSearchString:string;aSearchOptions: TStringSearchOptions): Boolean;
var
  Size : Integer;
Begin
      Size:=StrLen(aString);
      Result := SearchBuf(aString, Size, 0, 0, aSearchString, aSearchOptions)<>nil;
End;

并像这样调用它:
ExistWordInString('Go Delphi Go','Delphi',[soWholeWord,soDown]);

如果你只调用一次,可能不会有任何问题。但是如果你在循环中调用它(例如1000次或更多),首先使用Pos函数(如下所示)将会惊人地提高性能。

function ExistWordInString(const AString:string;const ASearchString:string;ASearchOptions: TStringSearchOptions): Boolean;
var
  Size : Integer;
  AWChar: PWideChar;
begin
   if Pos(LowerCase(ASearchString), LowerCase(AString)) = 0 then
   begin
      Exit(False);
   end;

   AWChar := PWideChar(AString);
   Size:=StrLen(AWChar);
   Result := SearchBuf(AWChar, Size, 0, 0, ASearchString, ASearchOptions)<>nil;
end;

0

这个函数可能不完全符合你的需求,但它非常接近:

希望它对你有用:

{ Copy all whole words from MainStr. The result will not have more than MaxChars characters. }

function CopyWords(MainStr: string; MaxChars: Integer): string;   
VAR EndsInSpace: Boolean;
    EndString, i: Integer;
    NextChar: char;
begin
 Assert(MaxChars > 0);
 EndString:= MaxChars;

 if Length(MainStr) > MaxChars then
  begin
   NextChar:= mainstr[MaxChars+1];

   if (MainStr[MaxChars] <> ' ') AND (NextChar <> ' ')
   then
     begin
      for i:= MaxChars downto 1 DO
       if MainStr[i]= ' ' then
        begin
         EndString:= i;
         Break;
        end
     end
   else
    if (MainStr[MaxChars]  = ' ')
    OR (MainStr[MaxChars] <> ' ') AND (NextChar = ' ')
    then EndString:= MaxChars;
  end;

 Result:= CopyTo(MainStr, 1, EndString);
 Result:= TrimRight(Result);
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接