Łańcuchy

Adam Boduch
Ten artykuł wymaga dopracowania!

Jeżeli możesz popraw ten artykuł według zaleceń, które możesz znaleźć na stronie [[Artykuły do poprawy]]. Po dopracowaniu tego tekstu można usunąć ten komunikat.

W tym artykule omówię funkcję operujące na tekście. Będą one umożliwiały takie działania jak dodawanie w wybrane pozycje jakichś znaków, odnajdywanie określonych wyrazów, zmianę tekstu na liczby (lub odwrotnie) i inne.

1 Przydatne Metody
     1.1 Copy
          1.1.1 LeftStr, RightStr
     1.2 Length
     1.3 Pos
     1.4 PosEx
          1.4.2 Lewostronne PosEx
     1.5 Delete
     1.6 Insert
     1.7 Format
     1.8 ExtractStrings
     1.9 Inne
          1.9.3 Concat
          1.9.4 StringOfChar
          1.9.5 Trim
          1.9.6 UpperCase, LowerCase
          1.9.7 ReverseString
     1.10 Ćwiczenie
2 Konwersje łańcuchów
     2.11 Zmiana z/na liczby
     2.12 Kody znaków ASCII
     2.13 Wartości Logiczne
     2.14 Data
          2.14.8 StrToDate
          2.14.9 StrToTime
3 Zakończenie

Przydatne Metody

Copy

Copy służy ono do kopiowania części znaków ze zmiennej.
var
  S, Finall : String;
begin
  S := 'Adres strony: http://4programmers.net';

  Finall := Copy(S, 1, 6) + 'e-mail: [email protected]';

  ShowMessage(Finall);
end;

Mamy sobie dwa stringi. Teraz do drugiego kopiujemy kawalek tekstu z pierwszego. W poleceniu Copy pierwszym parametrem musi być źródło wykonywanej operacji, drugi parametr to miejsce od którego będzie się zaczynała operacja kopiowania, a ostatni to ilość znaków do skopiowania.

LeftStr, RightStr

Te funkcje zwracają kawałek tekstu po odpowiednio lewej i prawej stronie. Drugim parametrem jest ilość znaków które zostaną skopiowane. Funkcje różnią się tylko tym, że w LeftStr kopiowanie zaczyna się od lewej strony, a w RightStr od prawej.
var
  S : String;
begin
  S := ' Jeden Dwa Trzy Cztery Pięć';
  ShowMessage(LeftStr(S, 6));    //Zobaczymy "Jeden"
  ShowMessage(RightStr(S, 11));  //Zobaczymy "Cztery Pięć"
end;

Jeżeli łańcuch zawiera wielobajtowy tekst, funkcja może zwrócić inną ilość znaków niż podano w parametrze. Funkcjami pochodnymi są LeftBStr oraz RightBStr, które traktują wszystkie znaki jako jednobajtowe.

Length

Dość często używana funkcja, to [[Delphi/Length]]. Zwraca długość tekstu. ```delphi var S : String; begin S := 'Delphi'; Length(S); //Zwróci 6 end; ```

Length służy też do zwracania ilości elementów w tablicy.

Pos

Kolejne bardzo przydatne polecenie. Otóż umożliwia ono przeszukiwanie określonego ciągu znaków w jakiejś zmiennej tekstowej. Przykładowo chciałbyś w jakiejś zmiennej odnaleźć spacje. ```delphi var S : String; begin S := 'Tekst zawierający spacje'; if Pos(' ', S) > 0 then //Jeżeli ciągu znaków nie ma w zmiennej, Pos zwróci 0 ShowMessage('W zmiennej znajdują się spacje.'); end; ``` W poleceniu Pos pierwszym parametrem jest szukany znak, a drugim źródło poszukiwań, czyli jak w naszym przykładzie zmienna S. W powyższym przykładze program poszukuje spacji w zmiennej. Jeżeli pozycja spacji będzie większa niż 0 (tzn. jeżeli tak jest) to wyświetla komunikat. Polecenie Pos używa się często w połączeniu z innymi - pokażemy to dalej...

PosEx

Następne polecnie jest bardzo podobne do zwykłego Pos'a z tym, że posiada pewien dodatkowy parametr - miejsce od którego chcemy zacząć szukać. ```delphi var S: String; begin s:= 'aaaa * bbbb * cccc'; PosEx('*', s, 7); end; ``` Otrzymamy wynik: 13, kiedy Pos() zwróciło by nam 6.
Pos(S, S2);
//jest równoważne
PosEx(S, S2, 1);

Lewostronne PosEx

Wiem z doświadczenia że czasami przy zabawie z łańcuchami przydałoby się znaleźć jakiś tekst który znajduje się nie **za** tekstem odniesienia (tak jak w przypadku funkcji [[Delphi/Pos]] i [[Delphi/PosEx]]) a **przed** nim. Takiej funkcji nie ma w potężnych modułach VCL, więc napisałem ją sobie sam.
function PosExBack(aSubStr, aStr: String; aOffset: Integer): Integer;
var Res: Integer;
begin
  Result := 0;
  Res := 0;
  aStr := Copy(aStr, 1, aOffset);
  repeat
    Res := PosEx(aSubStr, aStr, Res + 1);
    if Res > 0 then Result := Res;
  until Res = 0;
end;

Działa tak samo jak zwykłe PosEx, tylko że nie szuka tekstu za aOffset tylko przed nim.

Delete

Kolejne polecenie służy do usuwania określonego ciągu znaków ze zmiennej. Pierwszym jego parametrem jest zmienna, której dotyczyć będzie operacja, drugim od jakiego miejsca w zmiennej będzie dotyczyć usuwania, a ostatni parametr to ilość znaków do usunięcia:
var
  S : String;
begin
  S := 'Adres strony: http://4programmers.net';
  Delete(S, 1, 21);

  ShowMessage(s);
end;

Powyższa procedura wyświetli jedynie napis 4programmers.net (bez http://). Gdy już wiesz o co chodzi w poleceniu Delete oraz Pos można napisać procedurę usuwającą wszystkie spacje w zmiennej:

var
  S : String;
begin
  S := 'Tekst zawierający spacje';
  while Pos(' ', S) > 0 do
    Delete(S, Pos(' ', S), 1);

  ShowMessage(S);
end;

Powyższe komendy usuną wszystkie spacje w zmiennej i ponownie wyświetlą stringa. Zastosowanie tutaj pętli spowoduje, że na pewno wszelkie spacje zostaną usunięte.

Insert

Parametry w tej procedurze są trochę pomieszane dlatego, że jej pierwszym parametrem jest ciąg znaków, który ma być wstawiony, drugim jest źródło operacji, czyli zmienna, której dotyczyć będzie operacja, a ostatni - trzeci parametr to znak od którego zaczynać się będzie operacja dodawania ciągu:
var
  S : String;
begin
  S := 'Adres strony: 4programmers.net';
  Insert('http://', S, 15);

  ShowMessage(s);
end;

Format

Ta funkcja jest bardzo przydatna, gdyż umożliwia formatowanie tekstu.
var
  ImieKolegi, MojeImie: String;
  Wiek: Integer;
begin
  ImieKolegi := 'Bożydar';
  MojeImie := 'Gerwazy';
  Wiek := 17;
  ShowMessage(Format('Witaj %s, nazywam się %s i mam %d lat', [ImieKolegi, MojeImie, Wiek]));
end;

Zobaczymy oczywiście Witaj Bożydar, nazywam się Gerwazy i mam 17 lat. Może wygląda to skomplikowanie, ale w rzeczywistości to bardzo proste. Pierwszy parametr to tekst, która ma w sobie dziwne człony (mówię o %s i %d). W te miejsca zostaną po kolei ? wepchnięte ? łańcuchy z drugiego parametru. A co znaczą litery s i d? Te symbole odpowiadają odpowiednio stringowi i liczbie rzeczywistej. Więcej informacji w artykule Format.

ExtractStrings

Funkcja rozdziela łańcuch (trzeci parametr) według separatora/ów (pierwszy parametr), pomija tzn. "white spaces" (drugi parametr), i zapisuje do jakiejś zmiennej (czwarty parametr) np do [[Delphi/TStrings]], [[TStringList]] etc.
var
  TS: TStringList;
begin
  ExtractStrings([' '], [], 'jacek wacek placek lol', Memo1.Lines);
end;

Taki kod zapisze do Memo tekst:

jacek
 wacek
 placek
 lol

gdyby w drugim parametrze zamiast [] podać [#32] (kod spacji, czyli po prostu [' ']) tekst wyglądały tak:

jacek
wacek
placek
lol

Inne

Istnieją jeszcze mniej przydatne polecenia, rzadziej używane. Wymienię je poniżej.

Concat

Na początek polecenie Concat umożliwiające połączenie określonych wyrazów (bloków). Polecenie to jest bardzo rzadko stosowane bo zastępuje ono częściej używany operator + służący właśnie do łączenia znaków. Oto przykład:
var
  S: String;
begin
  S := '15 czerwca';
  ShowMessage(Concat('Dzisiaj jest ', S, ' roku 2012'));
end;

Nic nadzwyczajnego. Jedyne chyba jej zastosowanie to efekt estetyczny kodu, jeżeli łączymy więcej stringów.

StringOfChar

Nie robi ono nic specjalnego. Wpisz do programu taki kod: ```delphi ShowMessage(StringOfChar('A', 5)); ``` a zobaczysz `AAAAA`.

Bardzo podobną funkcją jest DupeString, z tym że umożliwia ona kopiowanie całych łańcuchów (nie tylko pojedynczych znaków).

Trim

Funkcja nie robi nic oprócz obcinania spacji na początku i na końcu stringa:
var
  S : String;
begin
  S := ' Adam Boduch ';
  ShowMessage(Trim(S)); //Zobaczymy samo "Adam Boduch"
end;

UpperCase, LowerCase

Te funkcje zmieniają litery w łańcuchu na duże ([[Delphi/UpperCase]]) oraz na małe ([[Delphi/LowerCase]]) litery.
ShowMessage(UpperCase('http://4programmers.net'));  //Zobaczymy "HTTP://4PROGRAMMERS.NET"
ShowMessage(LowerCase('[email protected]'));        //Zobaczymy "[email protected]"

ReverseString

Jak można wywnioskować po nazwie, funkcja zwraca odwrócony ciąg znaków. Po wywołaniu tego: ```delphi var S : String; begin S := ' Odwróć Mnie'; ShowMessage(ReverseString(S)); end; ``` Zobaczymy okienko z napisem "einM ćórwdO".

Ćwiczenie

Myślę, że dobrym podsumowaniem tego co dotychczas zrobiliśmy będzie program, który 'wygrzebie' ze stringa adres e-mail:
var 
  AtPos, LeftSidePos, MailLength, I: Integer;
  sText: String;
begin
  AtPos := Pos('@', sText);
  if AtPos > 1 then
    begin
      LeftSidePos := AtPos;
      while (sText[LeftSidePos - 1] in ['a'..'z', 'A'..'Z', '0'..'9', '-', '_', '.']) do
        Dec(LeftSidePos);

      MailLength := 0;
      while (sText[AtPos + MailLength + 1] in ['a'..'z', 'A'..'Z',  '.']) do
        Inc(MailLength);

      ShowMessage(Copy(sText, LeftSidePos, AtPos - LeftSidePos + MailLength + 1));
    end
      else
    ShowMessage('Podany tekst nie ma w sobie maila');
end;

Budowa nie jest zbyt skomplikowana. Na początek program w zmiennej odnajduje znak małpy, a później 'cofa się' w zmiennej aż napotka znak który nie może znajdować się w adresie. Następnie idzie od małpy do znaku który nie może znajdować się w domenie.

Konwersje łańcuchów

Zmiana z/na liczby

Do zmiany łańcucha na liczby i odwrotnie służą funkcje StrToInt oraz IntToStr.

var
  S: String;
  I: Integer;
begin
  S := '25';
  I := StrToInt(S);  //Teraz w I jest liczba 25
  ShowMessage(IntToStr(I));
end;

A co w przypadku jeżeli w S nie będzie liczby, albo będą oprócz niej inne znaki, np siema? W takim wypadku kompilator wyrzuci nam błąd 'siema' is not vaild Integer value. Możemy się przed tym zabezpieczyć dzięki takim funkcjom jak TryStrToInt lub StrToIntDef.

Istnieją odpowiedniki tych funkcji dla liczb zmiennoprzecinkowych, a są to StrToFloat oraz FloatToStr:

var
  S: String;
  D: Double;
begin
  S := '25.5';
  D := StrToFloat(S);  //Teraz w D jest liczba 25.5
  ShowMessage(FloatToStr(D));
end;

Dla tych funkcji również są ? bezpieczne ? odpowiedniki: TryStrToFloat i StrToFloatDef.

Kody znaków ASCII

Do zabawy takimi kodami służą funkcje [[Delphi/Ord]] oraz [[Delphi/Chr]]. Zamieniają one kolejno, znak na jego kod oraz odwrotnie.
var
  C: Char;
  I: Integer;
begin
  C := 'A';
  ShowMessage(IntToStr(Ord(C))); //Zobaczymy "65" > kod znaku "A";

   {Najpierw zamienimy to co jest w C ("A") na kod, następnie powiększymy o dwa, i znów zapiszemy}
  C := Chr( Ord(C)  +  2);  //Zwróci "C"
end;

Wartości Logiczne

Nie dla każdego te słowa są zrozumiałe. Wartości Logiczne to `True`/`False` (Prawda/Fałsz). Przykład takiej konwersji:
begin
  BoolToStr(True); //Zwraca "0"
  BoolToStr(False); //Zwraca "-1"
end;

Ta funkcja posiada jeszcze jeden parametr, jeżeli przyjmie on wartość True wtedy zwróci nam angielskie słowa odpowiadające wartościom.

begin
  BoolToStr(True,  True); //Zwraca napis "True"
  BoolToStr(False, True); //Zwraca napis "False"
end;

Data

Metod do wyświetlania, przechowywania, edytowania etc. dat jest tyle (7 stron, heh), że nie będę ich tu przepisywał i wymienię tylko kilka. Wszystkie są dostępne w module [[Delphi/Moduły/DateUtils]].

StrToDate

Te funkcja służy do konwertowania właśnie daty na tekst.

Funkcja Date zwraca aktualną datę.

begin
  ShowMessage(DateToStr(Data));
end;

Odpowiednikiem zmieniający tekst na datę jest StrToDate.

StrToTime

Z kolei ta, jak się nie trudno domyśleć konwertuje czas na tekst.

Funkcja Time zwraca aktualny czas.

begin
  ShowMessage(TimeToStr(Time));
end;

Odpowiednikiem jest StrToTime.

Zakończenie

Warto zapoznać się zarówno z modułem [[/Delphi/Moduły/StrUtils]] jak i z pozostałymi. Nie po to żeby wykuć wszystko co tam jest, tylko żeby popatrzeć na to co w nich siedzi, i poczytać dwa słowa. Często się zdarza że piszemy jakieś funkcje nie mając pojęcia, że programiści Delphi już o tym pomyśleli i odwalili robotę za nas. Więc warto trochę poczytać i douczyć się tylko po to żeby sobie oszczędzić czasu.

3 komentarzy

Spoko arcik, tylko ostatni przyklad niejest zaabardzo dopracowany, alemtakto spoko

Poważny błąd w ostatnim pzykładzie ponieważ kopiuje kawałek adresu od początku do małpy a po małpie już nie potrzeba by jeszcze 1 pętelkę która by szła po małpie aż napotka spacje

No dobra, wszystko fajnie, ale jak np. usunąć powtarzające się adresy www wpisywane do comboboxa (które są zapisywane w pliku) przy uruchomieniu stworzonego programu???? Jak to samo zrobić dla pustych wierszy w comboboxie, które nieraz się tworzą??? Jak coś to [email protected] DZIĘKI