Delphi stringlist trovando parole chiave negativa nella lista
-
19-09-2019 - |
Domanda
Ho due liste di stringhe che sto lavorando con. Uno che ha una lista di parole chiave, e poi un altro che ha una lista di parole chiave negativa. Voglio essere in grado di cercare attraverso la lista e scegliere le voci di elenco che non contengono la parola chiave negativa e di uscita a un terzo elenco di parole chiave. Stavo usando la funzione AnsiPos ma che ha trovato le parole chiave negativa se fossero parte di una parola, contro l'intera parola.
Qualche suggerimento su un modo relativamente semplice per fare questo? La velocità non è così importante, ma sarebbe bello.
Esempio di quello che sto cercando di fare:
Elenco parole chiave:
Cat Catfish Fish Sticks Dog Food
Negativo elenco di parole chiave:
Fish
valori restituiti Cerchiamo
Cat Catfish Dog Food
Questo è quello che ho finora .. che non funziona. Ho usato le informazioni da: C'è un efficiente Ricerca a Word funzione in Delphi?
function ExistWordInString(aString: PAnsichar; aSearchString: string;
aSearchOptions: TStringSearchOptions): Boolean;
var
Size : Integer;
begin
Size := StrLen(aString);
result := SearchBuf(aString, Size, 0, 0, aSearchString, aSearchOptions) <> nil;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
i, j, index: integer;
s: string;
stl: tstringlist;
begin
stl := TStringList.Create;
stl.Text := listbox1.Items.Text;
for I := 0 to stl.Count - 1 do
begin
for j := 0 to listbox2.Count - 1 do
begin
if not ExistWordInString(PAnsiChar(listbox2.Items.Strings[j]),
listbox1.Items.Strings[i], [soWholeWord, soDown])
then
listbox3.Items.Append(stl.Strings[i]);
end;
end;
end;
Soluzione
questo codice di esempio funziona come un fascino (utilizzando Delphi 7):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, StrUtils;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
ListBox2: TListBox;
ListBox3: TListBox;
procedure Button1Click(Sender: TObject);
private
function ExistWordInString(aString, aSearchString:string;aSearchOptions: TStringSearchOptions): Boolean;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
i,k: integer;
begin
for k:= 0 to ListBox2.Count -1 do
for i:= 0 to ListBox1.Count - 1 do
begin
if not ExistWordInString(ListBox1.Items[i], ListBox2.Items[k],[soWholeWord,soDown]) then
ListBox3.Items.Append(ListBox1.Items[i]);
end;
end;
function TForm1.ExistWordInString(aString, aSearchString: string; aSearchOptions: TStringSearchOptions): Boolean;
var
Size : Integer;
begin
Size:=Length(aString);
Result := SearchBuf(PChar(aString), Size, 0, 0, aSearchString, aSearchOptions)<>nil;
end;
end.
ed ecco la forma:
object Form1: TForm1
Left = 1008
Top = 398
Width = 411
Height = 294
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 320
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ListBox1: TListBox
Left = 8
Top = 8
Width = 177
Height = 97
ItemHeight = 13
Items.Strings = (
'Cat '
'Catfish'
'Fish Sticks'
'Dog Food')
TabOrder = 1
end
object ListBox2: TListBox
Left = 192
Top = 8
Width = 121
Height = 97
ItemHeight = 13
Items.Strings = (
'Fish')
TabOrder = 2
end
object ListBox3: TListBox
Left = 8
Top = 112
Width = 305
Height = 137
ItemHeight = 13
TabOrder = 3
end
end
Spero che questo aiuti.
Reinhard: -)
Altri suggerimenti
Se gli spazi sono l'unica parola delimitatore è necessario preoccuparsi, allora si può fare una partita di parola intera utilizzando AnsiPos con l'aggiunta di uno spazio prima e dopo il sia la parola chiave e la parola chiave negativa, vale a dire
AnsiPos ( ' '+ SubStr +'', ' '+ Str +'')
Avreste bisogno di un ciclo per controllare ogni voce dall'elenco parole chiave negativa.
Credo di aver capito. Utilizzare stringlist.find ( 'pesce', indice);
Non ho capirlo. .find non ha funzionato.
-Brad
È possibile utilizzare la funzione SearchBuf (vedi la risposta del pastacool) se si è non interessati ad altri personaggi, ad eccezione A..Z / Unicode.
Se si dispone di un Unicode Delphi (D2009 o D2010), allora è necessario utilizzare TCharacter.IsLetterOrDigit (aString: string; aIndex: integer): booleano; dalla Carattere unità. Un semplice esempio per voi per ottenere l'idea:
procedure TForm7.btn1Click(Sender: TObject);
var
bMatches: boolean;
begin
with rgx1 do //custom component - disregard it
begin
RegEx:=edtTextToFind.Text; //text to find
Subject:=mmoResult.Text; //text in which to search
if Match then //aha! found it!
begin
bMatches:=True;
if chkWholeWord.Checked then //be attentive from here!! - I think that's self explaining...
begin
if MatchedExpressionOffset>1 then
bMatches:=not TCharacter.IsLetterOrDigit(Subject, MatchedExpressionOffset-1);
if bMatches and (MatchedExpressionOffset+MatchedExpressionLength<=Length(Subject)) then
bMatches:=not TCharacter.IsLetterOrDigit(Subject, MatchedExpressionOffset+MatchedExpressionLength);
end;
if bMatches then //select it in the memo
begin
mmoResult.SelStart:=MatchedExpressionOffset-1;
mmoResult.SelLength:=MatchedExpressionLength;
mmoResult.SetFocus;
end
else
ShowMessage('Text not found!');
end
else
ShowMessage('Text not found!');
end;
end;
Cambia la funzione per leggere:
function ExistWordInString(aString:PAnsichar;
aSearchString:string;
aSearchOptions: TStringSearchOptions): Boolean;
var
b : boolean;
begin
if soWholeWord in aSearchOptions then
b := Pos(' '+Uppercase(aSearchString)+' ',' '+UpperCase(aString)+' ') > 0;
else
b := Pos(UpperCase(aSearchString),UpperCase(aString)) > 0;
Result := b;
end;
Se la vostra utilizzando Delphi 2009/2010 poi cambiarlo da Pos
a AnsiPos
. La mia ipotesi è che soWholeWord significa che la partita "Fish" potrebbe corrispondere a "bastoncini di pesce" ma non "pesce gatto".