2010-01-11 2 views
1

У меня есть два строковых списка, с которыми я работаю. Тот, у которого есть список ключевых слов, а затем другой, который имеет список минус-слов. Я хочу, чтобы иметь возможность выполнять поиск по списку и выбирать элементы списка, которые не содержат отрицательное ключевое слово и выводятся в третий список ключевых слов. Я использовал функцию AnsiPos, но нашел минус-слова, если они были частью слова, а также полным словом.Delphi stringlist, содержащий отрицательное ключевое слово в списке

Любые предложения относительно относительно простого способа сделать это? Скорость не так важна, но было бы неплохо.

Пример того, что я ищу делать: Список

Ключевое слово:

 
Cat 
Catfish 
Fish Sticks 
Dog Food 

Отрицательный Список ключевых слов:

 
Fish 

Возвращаемые значения Требуются:

 
Cat 
Catfish 
Dog Food 

Это то, что у меня есть до сих пор .. это не работает. Я использовал информацию: Is There An Efficient Whole Word Search Function 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; 

ответ

1

этот пример кода работает как шарм (с использованием 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 

надеюсь, что это помогает.

Reinhard :-)

+0

Спасибо всем, кто помог с этим. Это отлично работает для моих нужд! работайте с Delphi 10 при обновлении. – Brad

1

Я думаю, что я понял это. Используйте stringlist.find ('fish', index);

Я не понял это. .find не работает.

-Brad

+0

ps. для производительности, посмотрите на. Сортированное свойство, которое помогает. Надежно выполняйте свою работу намного быстрее. –

+1

Это не сработает. «Найти» не соответствует частичным строкам. Вам понадобится некоторый алгоритм, который выполняет сравнение «целое слово» для каждого слова в отрицательном списке по списку кандидатов. Ваше определение «целое слово» может быть очень специфичным (то есть, какие символы за пределами «пространства» и «начало строки/конца строки» составляют разрыв слова для целей сопоставления «слов». – Deltics

+0

Я просто понял это. . :( – Brad

2

Если пространства единственного слово разделителя вам нужно беспокоиться о том, то вы можете сделать весь матч слова, используя AnsiPos, добавив пробел до и после как ключевого слова и минус-слов, т.е.

AnsiPos (' '+ SubStr +'', ' '+ Str +'')

Вы должны были бы цикл, чтобы проверить каждую запись из списка минус-слов.

+0

Это может сработать ... похоже, немного взломать ... но было бы проще, чем что я делаю сейчас ..: P – Brad

+0

Не работает ... :(Все еще пытаюсь понять это ... – Brad

1

Вы можете использовать функцию SearchBuf (см ответ на pastacool в) ЕСЛИ вы не заинтересованы в других символов, кроме a..z/Unicode.

Если у вас есть Unicode Delphi (D2009 или D2010), вы должны использовать TCharacter.IsLetterOrDigit (aString: string; aIndex: integer): boolean; от Персонаж единица.Простой пример для вас, чтобы получить представление:

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

Изменить вашу функцию для чтения:

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 означает, что матч «Рыба» будет соответствовать «Fish Sticks», но не «сома».

Смежные вопросы