Список строк Delphi находит минус-слово в списке
-
19-09-2019 - |
Вопрос
У меня есть два списка строк, с которыми я работаю.Один со списком ключевых слов, а другой со списком минус-слов.Я хочу иметь возможность выполнять поиск по списку и выбирать элементы списка, которые не содержат минус-слово, и выводить их в третий список ключевых слов.Я использовал функцию AnsiPos, но она нашла минус-слова, если они были частью слова, а не полным словом.
Есть какие-нибудь предложения по относительно простому способу сделать это?Скорость не так уж важна, но было бы неплохо.
Пример того, что я хочу сделать:
Список ключевых слов:
Cat Catfish Fish Sticks Dog Food
Список минус-слов:
Fish
Требуемые возвращаемые значения:
Cat Catfish Dog Food
Это то, что у меня пока получилось..что не работает.Я использовал информацию из: Есть ли эффективная функция поиска по всему слову в 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;
Решение
этот пример кода работает как шарм (с использованием 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.
и вот форма:
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
надеюсь это поможет.
Рейнхард :-)
Другие советы
Если пробелы — единственный разделитель слов, о котором вам нужно беспокоиться, вы можете выполнить сопоставление всего слова с помощью AnsiPos, добавив пробел до и после оба ключевое слово и минус-слово, т.е.
AnsiPos(' '+SubStr+' ', ' '+Str+' ')
Вам понадобится цикл для проверки каждой записи из списка минус-слов.
Думаю, я понял это.Используйте stringlist.find('fish',index);
Я не понял этого..найти не получилось.
-Брэд
Вы можете использовать функцию SearchBuf (см. ответ Pastacool). ЕСЛИ ты нет интересуют другие символы, кроме A..Z/Unicode.
Если у вас Unicode Delphi (D2009 или D2010), вам необходимо использовать TCharacter.IsLetterOrDigit(aString:нить;aИндекс:целое число):логическое значение; из Характер единица.Простой пример для понимания:
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;
Измените свою функцию следующим образом:
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;
Если вы используете Delphi 2009/2010, измените его с Pos
к AnsiPos
.Я предполагаю, что soWholeWord означает, что совпадение «Рыба» будет соответствовать «Рыбным палочкам», но не «сому».