问题
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!
回答1:
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.
回答2:
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.
回答3:
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;
回答4:
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;
来源:https://stackoverflow.com/questions/1678572/is-there-an-efficient-whole-word-search-function-in-delphi