PosEx w odwrotnym kierunku Delphi

0

Czy analogicznie do funkcji POS, POSEX istnieje funkcja przeszukująca Memo.Text w kierunku odwrotnym: to znaczy zaczynając gdzieś pośrodku textu (np.od znaku nr1200) w kierunku początku dokumentu (zamiast w kierunku końca)?
Jeśli tak to jaka to funkcja?
jeśli nie to jak zrealizować takie wyszukiwanie?

Konkretnie jeśli znalazłem określony znak #9 (tabulacja pozioma) to jak znaleźć poprzedni (nie następny)?

0

Jeżeli interesuje Cię wyszukanie pojedynczego znaku to nie trzeba używać Pos/PosEx.
Sprawdzasz po prostu Memo.Text[i], iterując i w pętli. Aby znaleźć następne wystąpienie szukanego znaku zwiększasz i. Aby znaleźć poprzednie wystąpienie szukanego znaku zmniejszasz i.

0

To wiem ale nie o to mi chodzi.
Potrzebuję po prostu wyszukać poprzednie wystąpienie znaku bez żadnych pośrednich działań.

0
glebosz napisał(a)

Potrzebuję po prostu wyszukać poprzednie wystąpienie znaku bez żadnych pośrednich działań.

A nie możesz przeszukiwać ręcznie tekstu, tylko używając gotowych funkcji? Nie napiszesz sobie swojej? Przecież to nie takie trudne jak mogło by się wydawać; Z resztą jeśli szukasz tylko i wyłącznie pojedynczego znaku to niepotrzebnie kombinujesz z Pos i PosEx - najprościej tak jak @pelsta pisze - zwykła pętla sprawdzająca znak - inkrementujesz, jeśli przeszukujesz w stronę końca dokumentu, lub dekrementujesz licznik pętli jeśli przeszukujesz do początku doksa; Nic prostszego;

Tak samo nie problem napisać funkcję wyszukującą ciągi znaków w jedną i w drugą stronę; Musisz tylko dobrze pomyśleć;

1

Ja to bym zrobił tak

var 
  I, TextPos: Integer;
  SL : TStringList;
begin
  I := 1;
  SL := TStringList.Create;

  TextPos := Pos('tekst', Memo1.Text);
  while (TextPos > 0) do
    begin
      SL.Add(IntToStr(TextPos));
      Inc(I);
      TextPos := PosEx('tekst', Memo1.Text, I);
    end;

  //Teraz w SL są wszystkie pozycje tekstu w tekście. Możesz użyć pętli for...to..., albo for...downto, jakiej chcesz..
  
  SL.Free;
end;
0

@TomRiddle - to jest bardzo dobry sposób, ale jeśli chcemy przeszukiwać dokument od początku do końca;

Jeśli natomiast będziemy chcieli wykonać wyszukiwanie od konkretnego miejsca w tekście i określonym kierunku - trzeba będzie znacznie go zmodyfikować; Pisząc taką funkcję ręcznie wystarczy wykorzystać pętlę for .. to .. do od miejsca gdzie jesteśmy do początku / końca tekstu i odpowiednio dekrementując / inkrementując licznik w pętli sprawdzać kolejny znak a także, czy słowo zaczynające się od wyznaczonego indeksem znaku pasuje do wzorca; Prosta sprawa;

0

@Furious Programming:
Można też użyć mojego kodu wyżej, tylko potem sprawdzić czy pozycja mieści się w obszarze tekstu który chcemy przeszukać.

0

Właściwie żaden z tych sposobów nie satysfakcjonuje mnie.

Wyłuszczę dokładnie o co mi chodzi.
Chcę znaleŹć w tekście (MemoX.Text) słowo. To jest proste.
Ale teraz najważniejsze i najtrudniejsze: chcę ustalić Pos początku linii w której to słowo się
znajduje (czyli Pos dla #10).
Ustalenie Pos dla początku następnej lini jest proste ale dla bieżącej już proste nie jest. Odwoływanie się do MemoX.Line nie wchodzi w grę (zbyt wolne).
W ogóle znajdowanie wszystkich Pos(#10,Memo... poprzedzających słowo i np. wykonanie ich listy (stringlist czy array) nie podoba mi się.
Najprostszym byłoby aby funkcja 'Pos-podobna' przeszukiwała do tyłu (w kierunku początku dokumentu ).
Być może jednak najlepszym rozwiązaniem będzie zrobienie listy wszystkich #10 w dokumencie.

1

Najprostszym byłoby aby funkcja 'Pos-podobna' przeszukiwała do tyłu (w kierunku początku dokumentu ).

Wytłumacz mi dobry człowieku jaki masz problem żeby napisać taką funkcję?
Bo to jest tak proste, że ja nie widzę żadnego problemu żeby zrobić fora od wskazanej wartości w dół do 1 i sprawdzać czy dany element to #10 i jeżeli tak to exitować z iteracją aktualną a jeżeli dojdziemy do końca (początku?) i nic nie znajdziemy to zwracamy 0.

Czy widzisz jakiś straszny problem żeby to napisać? Bo ja nie.

0
glebosz napisał(a)

Najprostszym byłoby aby funkcja 'Pos-podobna' przeszukiwała do tyłu (w kierunku początku dokumentu ).
Być może jednak najlepszym rozwiązaniem będzie zrobienie listy wszystkich #10 w dokumencie.

Jedno nie, bo wolne, drugie nie, bo Ci się nie podoba... Zastanów się dobrze nad tym, bo w ten sposób nigdy nie napiszesz tego algorytmu...

@132 napisał Ci, żebyś sobie napisał swoją, z resztą nie tylko On, bo wszyscy praktycznie do tego zmierzają; Jeśli jest wolne, to popracuj w WinAPI, albo napisz szybszą kontrolkę; Masz jakiś pomysł? Bo mi się wydaje, że nie masz żadnego, a każdy pomysł, który podsunie Ci zainteresowany tematem jest zły... Jak masz tak marudzić, to nie pisz postów tylko weź się solidnie za robotę i napisz coś, co będzie Ci się podobało i działało wystarczająco szybko;

W komponencie z klasy TMemo masz właściwość CaretPos - zainteresuj się nią;

No i napisz w końcu jakiś kod, bo jak na razie nie zamieściłeś żadnego;

0
glebosz napisał(a)

Chcę znaleŹć w tekście (MemoX.Text) słowo. To jest proste.
Ale teraz najważniejsze i najtrudniejsze: chcę ustalić Pos początku linii w której to słowo się
znajduje (czyli Pos dla #10).

Zrób coś w tym stylu (trzeba dodać parę zabezpieczeń):

var
  SzukaneSlowo:string;
  p:Integer;
//...
  p:=Pos(SzukaneSlowo,MemoX.Text);
  Dec(p);
  while MemoX.Text[p]<>#10 do Dec(p);
0

Jeśli chcesz mieć bardzo szybki algorytm przeszukujący - zainteresuj się klasą TFindDialog i TReplaceDialog;

Pomocny będzie artykuł Find & Replace - Creating Notepad

0

Nie siedzę już tyle w Delphi co kiedyś, ale spróbuj czegoś takiego:

var
  SzukaneSlowo:string;
  iPos, iLine, iLineStart: integer;
...     
iPos := Pos(SzukaneSlowo, MemoX.Text);     
iLine := MemoX.Perform(EM_LINEFROMCHAR, iPos, 0) ;
iLineStart := MemoX.Perform(EM_LINEINDEX, iLine, 0) ;

Możliwe, że trzeba będzie skorygować iPos przed użyciem - jeśli MemoX.Text zawiera #13#10 a samo memo w środku tylko #13 lub #10.

0

wiem że to proste szukać od początku dokumentu do linii gdzie jest szukany wyraz.
Ale jeśli dokument jest bardzo długi (np 10 000 linii) to dotarcie do właściwej linii zajmie zbyt dużo czasu.
Najszybciej byłoby szukać #10 do tyłu bo byłaby tylko jedna linia do przeskoczenia.
Owszem sprawdzę możliwości CaretPos.

Kod od vpiotr-a :

var
SzukaneSlowo:string;
iPos, iLine, iLineStart: integer;
...
iPos := Pos(SzukaneSlowo, MemoX.Text);
iLine := MemoX.Perform(EM_LINEFROMCHAR, iPos, 0) ;
iLineStart := MemoX.Perform(EM_LINEINDEX, iLine, 0) ;

wydaje mi się obiecujący.
Przetestuję go jednak dopiero jutro i o wynikach napiszę :)

0
TomRiddle napisał(a)
  I := 1;
  TextPos := Pos('tekst', Memo1.Text);
  while (TextPos > 0) do
    begin
      SL.Add(IntToStr(TextPos));
      Inc(I);
      TextPos := PosEx('tekst', Memo1.Text, I);
    end;

Nie rozumiem gdzie jest błąd.

Załóżmy, że Memo1.Text:='ABCDEtekstABC', gdzie 'tekst' występuje tylko raz.
Ile razy go znajdzie ten algorytm i co będzie zawierał SL?

0

Tak.... to działa!!!! Dokładnie to co chciałem :)
Wspaniała funkcja. Prosta i efektywna.

var
SzukaneSlowo:string;
iPos, iLine, iLineStart: integer;
...
iPos := Pos(SzukaneSlowo, MemoX.Text);
iLine := MemoX.Perform(EM_LINEFROMCHAR, iPos, 0) ;
iLineStart := MemoX.Perform(EM_LINEINDEX, iLine, 0) ;

Warto było poczekać na sensowną wypowiedź człowieka o otwartym umyśle.

0

Tak twoja procedura też działa. Zwraca poczatek liniw której jest szukane słowo.

var
SzukaneSlowo:string;
p:Integer;
//...
p:=Pos(SzukaneSlowo,MemoX.Text);
Dec(p);
while MemoX.Text[p]<>#10 do Dec(p);

Funkcje Inc i Dec działają chyba na indexach. Nie wiem o nich zbyt wiele.

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