Wyszukiwanie w MEMO lub w pliku tekstowym

0

Witam, chodzę do drugiej klasy technikum informatycznego. Mam pewne zadanie do wykonania. Jest nim program "książka telefoniczna".
Program wygląda następująco
user image
Problem mam z wyszukiwaniem w pliku.txt kontaktu i zapisywaniu go do Edita.
Otóż po wpisaniu frazy wyszukiwania i kliknięciu szukaj, program działa mi w następujący sposób:

procedure TForm1.Button2Click(Sender: TObject);
var
 I:integer; 
begin
  for I:= 0 to Memo1.Lines.Count -1 do
  If E7.Text= Memo1.Lines[I] Then E6.Text:= Memo1.Lines.Strings[I];
end;

znajduje on wpisaną frazę ale tylko wtedy gdy dokładnie jest ona taka sama jak kontakt w lista.txt
Np. Mam kontakt w pliku lista.txt
Zawartość:
Norbert Kowalski 792538458 793845925 72137536
Jeżeli zaznaczę opcję (RadioButtona) Szukaj wg imienia i wpiszę
"Norbert" to program nie działa, dopiero jak wpiszę "Norbert Kowalski 792538458 793845925 72137536"

Rozumiem działanie tej procedury jednak mam problem z jej przerobieniem by działała poprawnie - by szukała tylko przy pomocy imienia lub nazwiska lub nr telefonu.
Program będzie oceniany jako projekt wszystkie inne warunki już gotowego programu już spełniłem pozostał mi tylko ten problem do rozwiązania, męczę już się z tym od wczoraj, dlatego proszę o pomoc.

0

Po pierwsze zacznij jakoś sensownie nazywać komponenty. Zamiast Edit1, Edit2 weź użyj edtImie, edtNazwisko, etc.
Po drugie lepszym wyjściem od trzymania danych w TMemo, byłoby trzymanie tego w tablicy.

Po drugie poczytaj o Pos(); i PosEx();

0

Dobra, program już działa :)

Teraz jest kolejny problem mianowicie przerobiłem program w ten sposób by tworzył plik tekstowy w którym znajduje się zawartość memo1.
Zawartość memo1.text:= Norbert Kowalski 166333999 888999777 555111222
Natomiast w plik.txt jest w nim taka zawartość: Norbert;Kowalski;166333999;888999777;555111222

Mój program zawiera 5 Editów : Imię, Nazwisko, Nr tel. 1, 2, 3
Jak zrobić by program po naciśnięciu buttona "wczytaj" wczytał z PLIKU .txt jego zawartość do poszczególnych Editów Imię: Norbert Nazwisko:Kowalski itd.?

0

Użyj ExtractStrings(); lub Plików INI. Osobiście polecam Ci to drugie, gdyż jest to absolutna podstawa.

0

Polecasz mi nowe rzeczy których w szkole, mnie jeszcze tego nie nauczyli... Może i masz racje że to absolutna podstawa jednak nauczyciel postawił wymaganie o czym wcześniej nie napisałem (mój błąd), by użyć tutaj nowej funkcji która za pomocą length przeszuka całą linijkę tekstu (pierwszy ";" i tekst zawarty przed nim ma dawać sygnał że jest to imię i analogicznie z nazwiskiem i telefonami) i wczytywała z pliku tekst do poszczególnych Editów. Wracając do plików ini - spotkałem się już z nimi i mniej więcej je kumam, tylko że jak bym je zastosował tutaj za bardzo bym wybiegł po za to co do teraz się uczyłem na programowaniu...
Jeżeli ktoś wie jak zarobić to za pomocą nowej funkcji to proszę napisać.

Co do ExtractStrings( ) zastosuję się do tej funkcji w swoim programie. No ale chciałbym przedstawić wersję programu wyglądającą tak jak nauczyciel sobie tego życzy :)

0

Sposób poniżej mało elegancki, ale jeżeli wykładowca upiera się na pętle i jest bez użycia Length, bo Length tutaj średnio się nadaje, a przynajmniej w krótkim czasie ja wpadłem na takie rozwiązanie.

const
  Separator = ';';
var
  S : string;
  I, Cnt : integer;
begin
  Cnt := 0;
  S := 'Norbert;Kowalski;166333999;888999777;555111222';
  if S <> '' then
  begin
    I := 1;
    repeat
      if S[I] = Separator then
      begin
        Cnt := Cnt + 1;
        case Cnt of
          1 : ImieEdit.Text := Copy(S, 1, I - 1);
          2 : NazwEdit.Text := Copy(S, 1, I - 1);
          3 : Tel1Edit.Text := Copy(S, 1, I - 1);
          4 : Tel2Edit.Text := Copy(S, 1, I - 1);
        end;
        Delete(S, 1, I);
      end
      else
      begin
        I := I + 1;
      end;
    until Cnt = 4;
    Tel3Edit.Text := S;
  end;
end;

A w przeciwieństwie do poprzednika do wydobyciu stringów w kolejnych itemach TStringList (indeksowane od zera, także 0 dla imiona, 1 dla nazwiska i tak dalej - poczytaj o komponencie TStringList) można się posłużyć łatwiejszą funkcją niż ExtractStrings, na przykład:

function Explode(Str : string; Separator : string) : TStringList;
var
  X : Integer;
begin
  Result := TStringList.Create;
  X := Pos(Separator, Str);
  while X > 0 do
  begin
    Result.Add(Copy(Str, 1, X - 1));
    if X <= Length(Str) then
    begin
      Str := Copy(Str, X + Length(Separator), Length(Str));
    end;
    X := Pos(Separator, Str);
  end;
  if (Length(Str) > 0) then
  begin
    Result.Add(Str);
  end;
end;

Poza tym co to za dziwny nauczyciel, co zamiast cieszyć się, że uczeń skorzystał z Internetu i znalazł sam rozwiązania (chociaż w Twoim przypadku tak nie jest, bo nie szukasz tylko pewnie od razu tutaj pytałeś), a w ogóle do takiego parsowania stringów wedlug separatora trzeba w sumie i tak jest najwygodniej korzystać z Pos, Copy oraz Delete.

0

Program mi działa gdy ta linijka nie jest zmieniona:

S := 'Norbert;Kowalski;166333999;888999777;555111222';

a jak przypisuję

S := Memo1.Text;

lub S := 'D:/lista.txt';

 program nie działa, nie wiem dlaczego ... może robię jakiś głupi błąd...
jak przypisać poprawnie zawartość Memo lub pliku tekstowego do stringa "S" by program zadziałał 
S jest potrzebny przy funkcji copy oraz Delete i moim zdaniem przypisanie wartości memo do stringa chyba nie będzie się kłóciło z tymi funkcjami?? 
błąd wywala mi przy tej linii: 
```delphi
 if S[I] = Separator then
0

a jak przypisuję
(1) S := Memo1.Text;
lub
(2) S := 'D:/lista.txt';
program nie działa, nie wiem dlaczego ... może robię jakiś głupi błąd...
jak przypisać poprawnie zawartość Memo lub pliku tekstowego do stringa "S" by program zadziałał
S jest potrzebny przy funkcji copy oraz Delete i moim zdaniem przypisanie wartości memo do stringa chyba nie będzie się kłóciło z tymi funkcjami??
błąd wywala mi przy tej linii:
(3)if S[I] = Separator then

  1. Przypisujesz cały tekst, wszystkie linie naraz
    2.Przypisujesz NAZWĘ pliku, nie jego zawartość.
    3.Bardzo niedobrze że ci błąd wywala. Może spróbuj coś zrobić żeby nie było błędu? Skasuj program? Albo zawsze możesz użyć głowy i powiedzieć DLACZEGO nie działa. Ale tego raczej nie zrobisz bo gdybyś umiał/mógł/chciał to już byś to zrobił.

Poczytaj sobie o TMemo.Lines
Widać że podstaw nie ogarniasz.

0

norbert.it: Ty masz myśleć co robisz. Zmienna S została celowo ustawiona na jedną linijkę jaką podałeś przykładowo. Jak tego nie ogarniasz, daruj sobie programowanie, zleć to komuś za godziwą zapłatę w dziale Praca na tym forum i po opłaceniu oraz uzgodnieniu szczegółów z ewentualnym zleceniobiorcą czekaj na gotowca. Przecież wiadomo, że jeżeli ma być użyta któraś z linijek Memo to zmiennej S trzeba przypisać te linijkę S := JakiesTwojeMemo.Lines[ZmiennaLubIndeksJakoCyfraAlboZmiennaLokalnaPętli];. Chciałeś tylko wiedzieć jak na przykładzie podanej linijki do odpowiednich Editów mają trafić odpowiednie pola po i przed średnikami. To takowy przycisk dostałeś. Programowanie to nie bezmyślne układanie komponentów na formatce, trzeba trochę samodzielności, logicznego myślenia oraz chęci napisania sensownego kodu, bo kod nie napisze się sam. A w ogóle to powinieneś użyć jak już plików typowanych, a do wyświetlenia samych nazwisk oraz imion użyć komponentu TListBox. A wszystkie dane wraz z dodatkowymi numerami telefonów lub co tam jeszcze wymyślisz można przechowywać w TList, TObjectList lub najprościej jako obiekty przez TwojListBox.Items.AddObject.... Więcej informacji znajdziesz w google, jeżeli tylko poszukasz. Powodzenia.

0

Gdy robię to w ten sposób:

S := Memo1.Lines.Text[j]; 

też nie działa
co do {3} to wiem dlaczego błąd wywala, jest kilka powodów i między innymi jest ten że źle przypisuję wartość Memo do stringa S

0

też nie działa

Cytując jednego z forumowiczów, nie działać to ci może podczas stosunku z kobietą. Umiesz podać przydatne informacje? Uczysz się na błedach? No chyba nie. No to bądź łaskaw nie pytać skoro nie umiesz... Albo się naucz.

I tak poza tym, ogarnij takie podstawy pascala/delphi jak: instrukcje przypisania, typy, tablice.

A jeżeli ci się nie chce... zapraszamy do działu praca!

0

Kolego,

działać
to znaczy też
wywoływać określony efekt
, dlatego też może to się odnosić do instrukcji jaką napisałem (która ma wywoływać określone działanie, a tego nie robi ), jak masz zamiar mnie poniżać
nie działać to ci może podczas stosunku z kobietą
to możesz mi napisać wiadomość prywatną a nie publicznie!

Umiesz podać przydatne informacje?
Co ci jest takiego potrzebne jak to, że zmienna do której chce przypisać wartość Memo to String(łańcuch, tablica), a memo to zwykłe pole tekstowe.

Przypisywanie

 S := Memo1.Lines.Text[j]; 

i wszelkiego rodzaju podobne struktury tego przypisywania nie działają
Dlatego postawiłem pytanie : jak poprawnie przypisać wartość memo do stringa - "S", jeżeli muszę zapisać to w trochę innej postaci, chociażby przy użyciu typu TMemo.Lines lub innych rodzajów to proszę mi powiedzieć dopiero zacząłem pracować na Delphi i nie wiem co dokładnie znaczą TMamo.Lines TStrings itd.

Nie wiem!
Dlatego się o to pytam, licząc na to że ktoś może mi pomóc. Dziękuję za pomoc jaką otrzymałem do tej pory, ale pisanie tekstów które mają na cel mnie obrazić w niczym mi nie pomoże, czy to jest takie trudne do zrozumienia ?!?

Edit:
Takich odpowiedzi oczekiwałem:

Memo to zmiennej S trzeba przypisać te linijkę S := JakiesTwojeMemo.Lines[ZmiennaLubIndeksJakoCyfraAlboZmiennaLokalnaPętli];
Dzięki niej zrozumiałem w czym tkwi błąd (została ona pogrubiona)wcześniej czy później bym sam do tego doszedł, jednak zdałem się na waszą pomoc by zrobić to szybciej.
A więc całość wrzuciłem do jeszcze jednej pętli for która rozpoczynała działanie od i:=0 do końca zawartości (linijek tekstu) w memo (Memo1.Lines.Count-1)...

Odpowiedź olesio którą zacytowałem mi wystarczyła, reszta była zbędna, naprawdę piszcie to co może wnieść do rozwiązania problemu.

daruj sobie programowanie

Nie jestem doskonały, nie wiem wszystkiego; każdy robi czasem głupie błędy, chyba lepiej jest je poprawić niż przekreślać całkowicie programowanie w delphi?

0

to możesz mi napisać wiadomość prywatną a nie publicznie!

Mogę, ale prywatnie, to byłby flame, tak to jest to próba uświadomienia ciebie o twoim błędzie.

Przypisywanie
S := Memo1.Lines.Text[j];
i wszelkiego rodzaju podobne struktury tego przypisywania nie działają

Na dole masz takie śmieszne okienko, w którym jest napisane DLACZEGO nie działa. Chodziło mi o treść tego śmiesznego okienka. No chyba że to runtime to wtedy podajesz wyjątek itd.

Dlatego się o to pytam, licząc na to że ktoś może mi pomóc. Dziękuję za pomoc jaką otrzymałem do tej pory, ale pisanie tekstów które mają na cel mnie obrazić w niczym mi nie pomoże, czy to jest takie trudne do zrozumienia ?!?

To nie ma na celu obrażenia ciebie.

Nie jestem doskonały, nie wiem wszystkiego; każdy robi czasem głupie błędy, chyba lepiej jest je poprawić niż przekreślać całkowicie programowanie w delphi?

Chyba lepiej jest się najpierw nauczyć podstaw niż pisać nierozumiejąc co się pisze. Bo robisz oczywiste błedy, widać że nie ogarniasz klas, tablic i innych rzeczy tym podobnych.

Więc ja kolego polecam: Ogarnij to czego nie ogarniasz a jak już będziesz mieć podstawy opanowane to pytaj. Bo tak to zadajesz oczywiste pytania, nie wiesz co piszesz a co za tym idzie także nie rozumiesz naszych rozwiązań. A z tego wynika że nie uczysz się na błedach i to że pomożemy tobie nic ciekawego nie da. Taka przynamniej jest moja opinia.

0

Ponieważ, właśnie robię te podstawowe błędy, pytam się chcąc uzyskać podpowiedź do rozwiązania problemu - chyba w ten sposób mogę uzupełniać luki. W trakcie robienia programów te luki się ukazują, dlatego też tutaj na forum zwróciłem się o pomoc w wykonaniu zadania.

Co do waszych rozwiązań to je w zupełności rozumiem, oczywiście oprócz tych rzeczy których po prostu jeszcze się nie uczyłem. A podstawy mam skoro tutaj piszę, a to że mam luki i chcę je uzupełnić to też świadczy o tym że szukam tutaj podpowiedzi, które uzyskałem i za to dziękuję.

0
S:=Memo1.Lines.Strings[j]; 
0

Znalazłem błąd mianowicie przy dodawaniu imienia, nazwiska lub telefonu nr 1 ciągu znaków gdy ich ilość była większa niż 9 to program źle potem je wczytywał do editów z memo
nie pisałem o pomoc gdyż uznalibyście to za podstawowy błąd ....

brakowało

I:=1;

po linijce: Delete(S, 1, I);

 żeby "I" wróciło po usunięciu na początek [jest na 5 znaku. czyli I to 5. usunie znaki od 1. do 5., a I nadal będzie na piątym, czyli dziesiątym itd., poza tym mam to wszystko wstawione do pętli for czyli dla każdego wiersza] (jak wierszy będzie kilka to najpierw się wpisze pierwszy do editów, później drugi usunie pierwszy i wstawi swoje, i tak dalej, aż nie dojdzie do końca i w wyniku tego w editach będzie zawartość ostatniego wiersza)

poprawny kod:
```delphi
procedure TForm1.Button6Click(Sender: TObject);
const
  Separator = ' ';
var
  S : string;
  I,j, Cnt : integer;
begin
 for j:=0 to Memo1.Lines.Count-1 do
  begin
   Cnt := 0;
   S := Memo1.Lines.Strings[j];
   if S <> '' then
   begin
     I := 1;
     repeat
       if S[I] = Separator then
       begin
         Cnt := Cnt + 1;
         case Cnt of
           1 : Eimie.Text := Copy(S, 1, I - 1);
           2 : Enazwisko.Text := Copy(S, 1, I - 1);
           3 : Etel1.Text := Copy(S, 1, I - 1);
           4 : Etel2.Text := Copy(S, 1, I - 1);
         end;
         Delete(S, 1, I);
         I:=1;   \\ <----
        end
       else
       begin
         I := I + 1;
       end;
     until Cnt = 4;
     Etel3.Text := S;
   end;
  end;
end;
end. 

Jednak program postanowiłem trochę ulepszyć (poprawić), a mianowicie by wczytywał zaznaczoną linijkę tekstu, w tym celu musiałem zmienić z memo na listbox.

0

Mam pytanie jak sprawdzić w funkcji pos ile jest wyników wyszukania (jeżeli jest ich więcej niż jeden)?

0

Poczytaj najpierw jak działa funkcja Pos: http://4programmers.net/Delphi/Pos - ona zwraca jeden wynik, dla pierwszego znaku pierwszego napotkanego słowa do wyszukania czyli w tekstcie S:= 'aaadupadupadupa; - Pos('dupa', S) zwróci cztery. To samo funkcja PosEx, która jednak szuka od offsetu czyli można pomijać część tekstu, w którym wyszukujemy.

0

no już rozumiem, zapomniałem że ona zwraca tylko numer, no właśnie to jak zrobić by jeżeli w tekście(listboxie) jest wiele słów o podanej frazie wyszukiwania, to żeby gdy znajdzie podany wyraz zaznaczyło go (ja zrobiłem tak że zaznacza mi całą linijkę tekstu gdzie został znaleziony wyraz) ale zaznacza mi tylko jedna linijkę mimo że w innych tez występuje to słowo i nie wiem jak to naprawić

0

jak zrobić by jeżeli w tekście(listboxie) jest wiele słów o podanej frazie wyszukiwania, to żeby gdy znajdzie podany wyraz zaznaczyło go

Musiałbyś obsłużyć znarzenie OnDrawItem, gdzie zaprogramowałbyś taką możliwość; Standardowo zaś podświetlany jest jeden item, czyli jedna linijka; Takie rzeczy można elegancko robić w TMemo czy TRichEdit dzięki FindDialog, ale nie ma takiej możliwości w TListBox; Poczytaj o OwnerDraw w TListBox i naucz się ręcznie malować itemy, a później zmodyfikuj kod pod kątem zaznaczania tylko słowa a nie całego itema;

Tu masz link do artykułu o OwnerDraw;

Jest to oczywiście do zrobienia, ale nie będzie to 20 linii kodu; Musisz poczytać o różnych technikach malowania itemów w komponentach i poznać metody i właściwości klasy TCanvas; Wykorzystasz tylko kilka, ale dobrze jest wiedzieć więcej na ten temat;

0

no cóż, już za mało czasu mam jutro o 10 oddaję program... dzięki za pomoc :)

0

więc masz jeszcze kilka godzin na wymodzenie genialnego (jak dla nauczyciela) kodu :P

0

Myślałem, że już nic nie wymyśle, aż tu nagle wpadł mi do głowy pomysł, by wyniki zapisywać do listbox'a. No i udało się dzięki LB mogę wyświetlać kilka wyników wyszukiwania na raz. Za miast wyświetlać pojedyncze wyniki w edit'cie program dodaje mi wynik do kolejnej linijki(count) listbox'a. Teraz programik w 100% działa i zostały w nim uwzględnione wszystkie wymagania nauczyciela :). Nauczyciel zgodził się przedłużyć termin oddania projektów do jutra, tak więc jutro oddam program i podzielę się ocenką jaką dostałem.

0

No to masz jeszcze czas na to, by zrobić wyszukiwanie tekstu w sposób, o którym pisałeś wczesniej; Zrób to zaznaczanie tylko szukanego ciągu w itemach, a nauczycielowi szczena opadnie (bo pewnie sam nie będzie tego umiał zrobić);

Masz tu artykuł o malowaniu, mały opis klasy TCanvas (raczej jego właściwości i metod), poczytaj trochę i zrób to jak należy;

Jeżeli chcesz to zrobić to czytaj, testuj różne kody i pytaj Google lub nas jak czegoś nie rozumiesz; Nie jest Ci do tego wiele potrzebne, Artykuł z 4P i parę zmiennych + główkowanie wystarczy (ewentualnie kawa :P);

Sam jestem ciekaw jaki będzie tego efekt; Jeżeli jesteć ambitny to możesz zrobić wyszukiwanie a la Opera - na żółtym tle podświetlone są wszystkie znalezione wyrazy, a na zielonym z ramką aktualnie pokazany; Wystarczy trochę pomyśleć i będziesz miał elegancki efekt;

0

programik oceniony na 4... nie na 5 ponieważ zabrakło :D automatycznego zapisywania książki telefonicznej do pliku przy wychodzeniu z programu, ale jest dobrze bo 4 na koniec z semestru z programowania mi wychodzi ;) teraz mam kolejny program do zrobienia na nowej kontrolce StringGrid'zie przy użyciu której mam zrobić grę kółko i krzyżyk, jak na razie doszedłem do tego jak zrobić bo po kliknięciu w jakieś pole stringgrid'a wpisywalo tam X lub O, nie wiem jeszcze jak podzielić to na 2 graczy 1 gracz X durgi O, jakieś podpowiedzi? :)

0

na razie doszedłem do czegoś takiego:

 procedure TForm1.GraSGClick(Sender: TObject);
var i,j,a,b:integer;
begin
 If (Imie1Edit.Text<>'')AND(Imie2Edit.Text<>'') THEN GraSG.Enabled:=TRUE;
 a:=0;
 b:=0;
 for i:=0 to 2 do
  begin
   for j:=0 to 2 do
    begin
      if a<b then GraSG.Cells[GraSG.Col,GraSG.Row]:='x' else GraSG.Cells[GraSG.Col,GraSG.Row]:='o';
      if GraSG.Cells[i,j]='x' then a:=a+1;
      if GraSG.Cells[i,j]='o' then b:=b+1;
    end;
   end;
  end;

niestety program źle działa gdy wpisuję na przekątnej

0

nie wiem jeszcze jak podzielić to na 2 graczy 1 gracz X durgi O, jakieś podpowiedzi?

No to czas najwyższy pomyśleć samodzielnie...

Możesz znak wpisywany po kliknięciu przechowywać w zmiennej typu Char:

var
  cCurChar: Char;

Podczas startu gry rozpoznajesz to, który gracz zaczyna i wpisujesz jego znak do zmiennej:

cCurChar := 'X'; //np.

No a podczas kliknięcia i sprawdzenia czy pole jest puste itd. Wpisujesz znak:

sgStage.Cells[X, Y] := sCurChar;

if cCurChar = 'X' then
  cCurChar := 'O'
else
  cCurChar := 'X';

Zmień warunek sprawdzający jaki jest aktualny znak, bo debilnie wygląda... Zależy jak przechowasz ten znak, możesz użyć tablicy i prościej i bardziej elegancko go zmienić;

EDIT: Poczytaj o notacji węgierskiej bo dziwnie nazywasz komponenty... :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1