[delphi] jeżeli linia w memo

0

Witam,

Chciałbym zrobić coś takiego, że jeśli linia w memo1 zawiera znak, który podam w Edit to przekopiuje mi ta linię do memo2 i usunie ja z memo 1.

I problem w tym, że nie wiem jak się do tego zabrać.
Czytam czytam i znajduje jedynie coś z AnsiMatchText ale kompletnie nie wiem jak to zastosować.

2

Proste problemy -> dział Newbie!

Z głowy, bez sprawdzania, więc sprawdź sobie i ew. popraw:

var
   x : integer;
begin
   x := 0;
   while x < Memo1.Lines.Count  do
      begin
      if Pos(Edit1.Text, Memo1.Lines.Strings[x]) > 0 then
         begin
         Memo2.Lines.Add(Memo1.Lines.Strings[x]);
         Memo1.Lines.Delete(x);
         end
            else
               x := x + 1;      
      end;

Skopiuj ideę, a nie kod :)

Ps. Ponieważ mi się nudzi, więc mała analiza programu (przyjmijmy, że w Memo1 jest 5 linii indeksowanych od 0 do 4):

  1. Zazwyczaj do poruszania się po elementach Memo używamy pętli for to do w postaci:
var
   x : integer;
begin
for x := 0 to Memo1.Lines.Count - 1 do
   begin
   //x w pętli przyjmuje zatem wartości od 0 do 4 (5-1)
   //tutaj robimy coś z linią memo o indeksie x
   end;
  1. Równie dobrze możemy użyć pętli while:
var
   x : integer;
begin
   x := 0;
   while x < Memo1.Lines.Count do
      begin
      //x w pętli przyjmuje wartości od 0 do 4 (x o wartości 5 już nie przejdzie, bo nie spełnia warunku)
      //tutaj robimy coś z linią memo o indeksie x
      x := x + 1;
      end;
  1. Równie dobrze możemy użyć pętli repeat until
var
   x : integer;
begin
   x := 0;
   repeat
   //x w pętli przyjmuje wartości od 0 do 4 (kiedy x przyjmie wartość 5, warunek spowoduje wyjście z pętli)
   //tutaj robimy coś z linią memo o indeksie x
   x := x + 1;
   until (x < Memo1.Lines.Count);

Tutaj zadaniem jest usuwanie linii spełniających jakiś warunek, więc w czasie pracy programu liczba linii się zmienia, co sprawia, że pętla for to do o stałej (niezależnej od żadnych warunków) liczbie przebiegów odpada. Ale zgodnie z powyższym do wyboru pozostają mi jeszcze dwie pętle while do i repeat until - i właściwie obydwu moglibyśmy tu użyć. No dobra, wybieramy while do.

I zasada jest prosta - sprawdzamy czy linia zawiera szukany ciąg (Instrukcja Pos):

  • jeżeli nie, to przechodzimy do sprawdzenia kolejnej linii memo x := x + 1
  • jeżeli tak, to dodajemy linię do memo2 i usuwamy linię z memo1 - tu można zauważyć, że jeśli usuniemy linię o indeksie np. 3, to linia o indeksie 4 staje się linią o indeksie 3. Więc ponownie musimy sprawdzić linię o takim samym indeksie, jak sprawdzaliśmy przed chwilą. Wystarczy więc, że pozwolimy na kolejny przebieg pętli bez zwiększania wartości x.

Jeśli jasne dawać plusiki za post :)

1
```delphi while x < Memo1.Lines.Count do ``` A czy tu się nie zcrarshuje ? ```delphi while x < Memo1.Lines.Count-1 do ``` U mnie jak dawałem pętle, to zawsze musiałem dawać 'Count-1', ponieważ inaczej był komunikat o przekroczeniu czegoś tam... Edit: Racja...Kod madmike'a jest poprawny.
1

Patryk27, zastanów się chwilę i na pewno dojdziesz do wniosku, że kod który podał **madmike **jest poprawny (nic się nie wysypie). Zwróć uwagę na operator porównania i pętlę jaką zastosował madmike. Ty zapewne masz na myśli pętlę for

0

OK zaraz zabieram się za pisanie;)
Dziękuje bardzo za pomoc Panowie.

:)

2

Zainspirowany "małym wykładem o pętlach", jaki przedstawił madmike, chciałem jeszcze dopowiedzieć jedną rzecz istotną zwłaszcza w kontekście problemu, z którym zwrócił się autor wątku. Myślę o pętli for. W Delphi (Pascalu) istnieje również pętla for w postaci for downto do, o czym często się zapomina, a jej zastosowanie w niektórych przypadkach upraszcza kod.

Problem, który przedstawił **effektiveddd **można rozwiązać również w ten sposób

var i: Integer;
begin
  for i:= Memo1.Lines.Count - 1 downto 0 do
    if Pos(Edit1.Text, Memo1.Lines[i]) > 0 then
    begin
      Memo2.Lines.Add(Memo1.Lines[i]);
      Memo1.Lines.Delete(i);
    end;
end;

Pętli for to do nie za bardzo można tutaj zastosować, bo Memo1.Lines.Count może się zmieniać wraz z przebiegiem pętli, a po skasowaniu jednej linii indeks następnej zmniejszy się o 1 i nie zostanie ona w ogóle sprawdzona. W przypadku pętli for downto do nie ma to znaczenia, bo będą się zmieniać indeksy linii, które już zostały sprawdzone.

Dla mnie taki kod jest najbardziej intuicyjny do zrozumienia, od razu widać, co robi. Kod, który podał **madmike **oczywiście też nie jest skomplikowany, ale chwilę (krótką, ale jednak) musiałem się zastanowić, dlaczego jest tam else

PS. Jak widać, mnie również się nudziło. Pozdrawiam tych, którzy się nudzą i nie tylko :)

1

O, widzisz, zapomniałem o for downto do... Dla mnie rozwiązanie z while do jest po prostu bardziej algorytmiczne. Ale to kwestia gustu i jak widać jest wiele rozwiązań jednego problemu :)

0

;) Dziękuje serdecznie za pomoc oraz wytłumaczenie ;))
A także za pomoc w dobraniu odpowiedniej pętelki do poprawnego działania.

0

I na koniec (1) pozwolę sobie na małe podsumowanie. Mam wrażenie, że większość adeptów programowania czytając o pętlach zatrzymuje się na pętli for to do, dalej już nie czytając. A przecież pozostałe się przydają.

Tutaj krótszym rozwiązaniem niewątpliwie było użycie for downto do. Chociaż ja sam jednak nadal bym używał while do. Po prostu, tak jak wspomniałem, jest to zapis bardziej algorytmiczny.

I na koniec (2) małe rozwinięcie twojego tematu jako przykład, że pętla while do może być niezastąpiona:

Przyjmijmy, że nasze memo to miejsce, gdzie trafiły komunikaty z systemu. Niektóre, uważamy za mało istotne, więc je usuwamy (czyli to co robimy z liniami, które zawierają jakiś znak).

W tym przypadku pętla for downto do świetnie się sprawdzi, bo znamy początkową liczbę linii z komunikatami w memo (Idziemy od góry do dołu).

A teraz wyobraź sobie, że w trakcie usuwania linii, system coś nam podrzuci, czyli doda kolejną linię w memo. Pętla for downto do nie zauważy w ogóle tego faktu i zignoruje te dodane linie. Pętla while do przy każdym przebiegu sprawdza, czy ponad tym co już przeleciała jeszcze coś jest i weźmie to pod uwagę przy ewentualnym usuwaniu.

Konkluzja: pamiętaj o tym, że nie jedno for tworzy pętle. :)

I na koniec (3), już jako swojego rodzaju przekomarzanie się:

simplex napisał(a)

Pętli for to do nie za bardzo można tutaj zastosować, bo Memo1.Lines.Count może się zmieniać wraz z przebiegiem pętli, a po skasowaniu jednej linii indeks następnej zmniejszy się o 1 i nie zostanie ona w ogóle sprawdzona.

var
   i: Integer;
begin
   for i:= 0 to Memo1.Lines.Count - 1 do
      if Pos(Edit1.Text, Memo1.Lines[Memo1.Lines.Count - 1 - i]) > 0 then
         begin
         Memo2.Lines.Add(Memo1.Lines[Memo1.Lines.Count - 1 - i]);
         Memo1.Lines.Delete(Memo1.Lines.Count - 1 - i);
         end;

Wiem, że to jest odwracanie kota ogonem, ale dowód, że jeśli się bardzo chce, to wszystko można :)

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