Kopiowanie pomiedzy liniami

0

Mam taki problem do rozwiązania. Chodzi mi o to, że jeśli wyszukam wartość pomiędzy liniami ---- np 6 to chodzi mi o to ażeby skopiować wszystko co znajduje się między owymi liniami wraz z liniami. Odległości między liniami mogą być różne.

--------------------
1
2
3
4
--------------------
5
6
1
2
--------------------
3
4
5
6
--------------------
6
5
--------------------

Zatem powinienem uzyskać takie coś:

--------------------
5
6
1
2
--------------------
3
4
5
6
--------------------
6
5
--------------------

Jak tego dokonać ?

Do tej pory mam coś takiego ale nie działa gdyż kopiuje w dół ;(

var
i, ii : integer;
sl, sl1 : TStringList;
begin
  sl := TStringList.Create;
  sl1 := TStringList.Create;

  sl.Text := ListBox1.Items.Text;

  for i := sl.Count -1 downto 0 do
   if pos('6', sl[i]) > 0 then
    begin

     ii := i;

     for ii := ii downto ii - 60 do
     begin
       sl1.add(sl[ii]);

       if pos('--------------------', sl[ii]) > 0 then
       break;
       end;

     end;

     Showmessage(sl1.Text);

  sl.Free;
  sl1.Free;

dodanie znaczników <code> - fp

0

@Bruno(M) - słabo opisałeś problem, ale mniej więcej rozumiem co chcesz zrobić; Jeśli chodzi Ci o to, że w danej liście łańcuchów oddzielonych liniami wyszukujesz daną wartość, to jeśli w danej sekcji znajduje się szukana wartość, to kopiujesz całą sekcję razem z liniami; Pomijane są te sekcje, które szukanej wartości nie zawierają;

Czyli dla przykładu mająt takie wejście:

--------------------
1
2
--------------------
4
5
--------------------
1
2
--------------------
7
8
--------------------

i szukając wartości np. 1, na wyjściu dostaniemy:

--------------------
1
2
--------------------
1
2
--------------------

czyli sekcję pierwszą i trzecią, tak?


Masz tutaj prosty algorytm realizujący Twoje założenia (pod warunkiem, że dobrze zrozumiałem co dokładnie chcesz zrobić):

const
  BREAK_LINE_CHAR = '-';
  BREAK_LINE      = '--------------------';
var
  slInput, slOutput: TStrings;
  intSecBgnIdx, intSecEndIdx, I, J: Integer;
  ansiNumber: AnsiString;
begin
  { tymczasowe listy wejścia i wyjścia }
  slInput := TStringList.Create();
  { pobranie z komponentu szukanej wartości }
  slOutput := TStringList.Create();
  try
    { skopiowanie listy wejścia do listy tymczasowej }
    slInput.Assign(memInput.Lines);
    ansiNumber := edtNumberToFind.Text;

    { sprawdzenie ilości linii w liście wejścia }
    if slInput.Count > 0 then
    begin
      I := 0;

      { dopóki licznik pętli jest mniejszy lub równy ilości linii w liście }
      while I < slInput.Count do
        { jeśli aktualna linia zawiera szukaną liczbę }
        if slInput[I] = ansiNumber then
        begin
          { ustawienie początkowych ideksów sekcji }
          intSecBgnIdx := I;
          intSecEndIdx := I;

          { szukanie początku sekcji razem z linią separatora }
          repeat
            Dec(intSecBgnIdx);
          until slInput[intSecBgnIdx][1] = BREAK_LINE_CHAR;

          { szukanie końca sekcji bez linii separatora }
          while slInput[intSecEndIdx + 1][1] <> BREAK_LINE_CHAR do
            Inc(intSecEndIdx);

          { skopiowanie linii sekcji bez końcowej linii separatora }
          for J := intSecBgnIdx to intSecEndIdx do
            slOutput.Add(slInput[J]);

          { ustawienie licznika pętli na indeks linii końca sekcji + 1 }
          I := intSecEndIdx + 1;
        end
      else
        { jeśli aktualna linia nie zawiera szukanej liczby - zwiększenie licznika pętli }
        Inc(I);

      { jeśli lista wyjścia nie jest pusta - dodanie końcowej linii separatora }
      if slOutput.Count > 0 then
        slOutput.Add(BREAK_LINE);

      { przepisanie listy tymczasowej do komponentu wyjścia }
      lbOutput.Items.Assign(slOutput);
    end;
  finally
    slInput.Free();
    slOutput.Free();
  end;
end;

Ten kod podpiąłem pod zdarzenie przycisku w aplikacji testującej i działa elegancko pod warunkiem, że format danych wejściowych jest poprawny; Algorytm możesz sobie zabezpieczyć, jeśli wejście może być błędnego formatu; Tak poza tym jest dobrze - sprawdziłem m.in. dane podane przez Ciebie w poście wyżej - wyjście dokładnie takie samo;

Sprawdzanie czy linia jest separatorem odbywa się nieco inaczej, bo wystarczy sprawdzić, czy pierwszy znak linii to znak - i jeśli tak - jest separatorem; Jeśli liczby mogą być ujemne - trzeba to będzie zabezpieczyć, ale to już pozostawiam Tobie;

W załączniku dodaję aplikację testującą (skopilowany exe) i pliki projektu, jednak napisanego w Lazarusie - kod i tak powinien być w pełni kompatybilny z różnymi wersjami Delphi, ponieważ nie zawiera jakichś sztuczek;

0

Dziękuję Furious Programming jednak zrobiłem to tak po amatorsku tak jak potrafię :

var
i, ii , iii: integer;
sl, sl1, sl2 : TStringList;
s1, s2 : string;
begin
  sl := TStringList.Create;
  sl1 := TStringList.Create;
  sl2 := TStringList.Create;

  sl.Text := ListBox1.Items.Text;

  for i := 0 to sl.Count -1 do
   if (pos('--------------------', sl[i]) > 0) then
     sl1.add(inttostr(i));

  for i := 1 to sl1.Count -1 do
  begin
   s1 := sl1[i-1];
   s2 := sl1[i];

  for ii := strtoint(s1) to strtoint(s2) do

   if pos('6',sl[ii]) > 0 then

  for iii := strtoint(s1)+1 to strtoint(s2) do
  begin

  sl2.Add(sl[iii]);
  end;

  end;

   sl2.Insert(0,'--------------------');

   Showmessage(sl2.Text);

  sl.Free;
  sl1.Free;
 sl2.Free;
0

A nie można prościej:

var sc:TStringList;
var pos,i,k:Integer;
var keep:Boolean;
begin
  sc:=TStringList.Create;
  try
    sc.Assign(ListBox1.Items);
    pos:=-1;
    keep:=true;
    for i:=ListBox1.Items.Count-1 downto 0 do
    begin
      if Pos('--------------------',sc[i])>0 then
      begin
        if not keep then for k:=i+1 to pos do sc.Delete(k);
        pos:=i;
        keep:=false;
      end
      else keep:=(keep)or(pos('6',sc[i])>0);
    end;
    ShowMessage(sc.Text);
  finally
    sc.Free;
  end;
end;

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