Question

In Delphi 2009 or later (Unicode), are there any built-in functions or small routines written somewhere that will do a reasonably efficient whole word search where you provide the delimiters that define the word, e.g.:

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;

where:

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

I only need this to return a true or false value if the "Word" is in the string.

There must be something for this somewhere, because the standard Find Dialog has "Match whole word only" as one of it's options.

How is this normally (or best) implemented?


Conclusion:

RRUZ's answer was perfect. The SearchBuf routine was just what I needed. I can even go into the StrUtils routine, extract the code, and modify it to fit my requirements.

I was surprised to find that SearchBuf doesn't first search for the word and then check for delimiters. Instead it goes through the characters of the string one at a time looking for a delimiter. If it finds one, then it checks for the string and another delimiter. If it doesn't find it, it then looks for another delimiter. For efficiency's sake, that's very smart!

Was it helpful?

Solution

You can use the SearchBuf function with the [soWholeWord] option.

function SearchBuf(Buf: PAnsiChar; BufLen: Integer; SelStart: Integer; SelLength: Integer; SearchString: AnsiString; Options: TStringSearchOptions): PAnsiChar;

See this example

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;

Use it this way

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

Bye.

OTHER TIPS

Just because Delphi's editor has a "word match" function, that doesn't mean the Delphi library offers it!

Typically, in most languages the way to go for this is a regular expression. Seems they're (still) not built into Delphi, as there are 3rd party libraries offering the capability. The first example I found is: http://delphi.about.com/od/toppicks/tp/delphi-regular-expressions.htm .

Typically, you'd build a regular expression something like

myRegex = '[' + Delim + ']+' + Word + '[' + Delim + ']+';
if regexSearch (Str, myRegex) then ...

You'll want to get details from the documentation of the library you get. My example doesn't correctly handle the case of the word starting at the beginning of Str or ending at its end, or being all of Str.

This function is not exactly what you need but it is pretty close:

I hope it is useful:

{ 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;

If you have function like below

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;

and call it like this:

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

You may not fell any problem if you call it once. But if you call this in a loop (for example 1000 times or more) first using Pos function (like below) will surprisingly give you extra performance

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top