Turbo Pascal. Programowanie

Turbo Pascal.
Programowanie

Autor: Tomasz M. Sadowski
Format: B5, stron: 136

Copyright © 1996 by Wydawnictwo Helion
wersja spakowana

helion.pl

Łańcuchy

Dane tekstowe mają - obok grafiki - największy udział w objętości informacji przetwarzanej i przechowywanej we współczesnych systemach komputerowych. Z tego też względu każdy szanujący się język wysokiego poziomu jest wyposażony w mechanizmy pozwalające na reprezentowanie, przechowywanie i przetwarzanie tekstów. W Turbo Pascalu służy do tego typ łańcuchowy (string), którym zajmiemy się w tym rozdziale. Dowolny tekst (łańcuch, ang. string) przechowywany jest w programie w postaci ciągu znaków, który może być interpretowany jako specyficzna tablica

array[0..255] of char

Przykładowa deklaracja zmiennej łańcuchowej ma postać

  var
    Napis : string;

Stałe łańcuchowe zapisuje się natomiast w postaci ciągów znaków ujętych w apostrofy (podobnie jak stałe znakowe):

  const
    STALY_NAPIS = 'Turbo Pascal';

Zerowy element łańcucha przechowuje jego aktualną długość (tzw. długość dynamiczną); będąc typu znakowego może on przyjmować wartości od 0 do 255. Stąd właśnie wynika ograniczenie długości łańcucha do 255 znaków, co zresztą w większości przypadków wystarcza aż nadto. Aby "skrócić" łańcuch (dana typu string zajmuje zawsze 256 bajtów, niezależnie od rzeczywistej długości tekstu), można wykorzystać deklarację

nazwa-zmiennej : string[długość]

Możliwość ta jest szczególnie cenna, jeśli w programie wykorzystujesz np. tablicę łańcuchów: deklarując element składowy tablicy jako string[20] oszczędzasz 235 bajtów, co przy stu elementach daje zysk ponad 20 kB. Warto zauważyć, że próba zapisania do "skróconego" łańcucha tekstu dłuższego niż pozwala deklaracja nie spowoduje błędu, a jedynie obcięcie nadmiarowych znaków.

Operacje na łańcuchach w zasadzie nie różnią się zapisem od operacji na zmiennych typu prostego i nie wymagają stosowania żadnych specjalnych sztuczek. Do wprowadzania, wyprowadzania i przypisywania łańcuchów wykorzystuje się - podobnie jak dla zmiennych typów prostych - procedury read(ln), write(ln) oraz operator przypisania. Również porównanie dwóch łańcuchów zapisywane jest identycznie, przy czym "wewnętrznie" odbywa się ono przez porównanie kodów odpowiadających sobie znaków. Tak więc:

  'C' < 'Pascal' (kod ASCII znaku 'C' jest mniejszy od kodu 'P')
     
  'c' > 'Pascal' (kod ASCII znaku 'c' jest większy od kodu 'P')
     
  'C' > '' (dowolny łańcuch jest większy od łańcucha pustego)

Z rzeczy prostych pozostało jeszcze dodawanie łańcuchów, polegające na ich zwykłym "sklejaniu" (niestety, łańcuchów nie da się odejmować, mnożyć ani dzielić). Jeżeli zmienna lancuch1 zawiera tekst 'Turbo', zaś lancuch2 - tekst 'Pascal', to wynikiem sklejenia obu zmiennych:

wynik := lancuch1 + lancuch2;

będzie oczywiście tekst 'TurboPascal'.

Również odwołania do poszczególnych znaków łańcucha realizuje się w sposób elementarny. Ponieważ może on być traktowany jako tablica znaków, instrukcja

s[5] := 'x'

wstawi znak x na piątą pozycję w łańcuchu s.

Bardziej wymyślne operacje na łańcuchach wymagają użycia specjalnie do tego celu przeznaczonych funkcji, z których najważniejsze opisano poniżej:

  Length(s) - zwraca bieżącą długość łańcucha s;
     
  Concat(s1, s2) - skleja łańcuchy s1 i s2 (podobnie, jak operator +)
     
  Copy(s, m, n) - zwraca podłańcuch o długości m znaków wycięty z łańcucha s poczynając od pozycji n;
     
  Pos(ch, s) - zwraca numer pozycji, na której w łańcuchu s znajduje się znak ch;
     
  Delete(s, m, n) - usuwa n znaków z łańcucha s poczynając od pozycji m.

Jak powiedziano wyżej, aktualną długość łańcucha można odczytać funkcją Length (lub przez bezpośrednie odwołanie do zerowej komórki łańcucha). Aby zmienić długość dynamiczną łańcucha, musisz użyć konstrukcji

s[0] := chr[n]

gdzie n jest żądaną długością (ponieważ łańcuch składa się ze znaków, musimy przekształcić liczbę n na odpowiadający jej znak funkcją chr). Ponieważ operacja ta czasem przynosi niezbyt pożądane efekty, lepiej jej unikać.

Przytoczony poniżej program Lancuchy demonstruje niektóre możliwości obróbki łańcuchów i w zasadzie nie wymaga dodatkowego komentarza. Poza wywołaniami opisanych wyżej procedur znalazła się w nim również funkcja UpCase, przekształcająca małą literę alfabetu na dużą. Operuje ona co prawda na typie znakowym, jednak typowe jej zastosowanie sprowadza się do konwersji całych łańcuchów, jak pokazano niżej.

  program Lancuchy;
  { Demonstracja operacji na łańcuchach }
   
  const
    TP = 'Turbo Pascal to bomba';
   
  var
    s1, s2 : string;
    i : integer;
   
  begin
    s1 := TP; { przypisanie }
    s2 := ''; { j.w., łańcuch pusty }
   
    for i := 1 to Length(s1) do
      s2 := s2 + ' '; { dodawanie łańcuchów/znaków }
    writeln(s1);
   
    i := Pos('a', s1); { wyszukanie znaku }
    s2[i] := '^'; { wstawienie znaku }
    writeln(s2); { i co z tego wynikło? }
   
    Delete(s1, 1, 6); { usunięcie części łańcucha }
    writeln(s1);
   
    for i := Length(s1) downto 1 do { wypisanie łańcucha }
          { od tyłu }
      write(s1[i]);
    writeln;
   
    for i := 1 to Length(s1) do { zamiana na duże znaki }
      write(UpCase(s1[i]));
    writeln;
   
    s1 := Copy(TP, 1, 13); { wycięcie podłańcucha }
    for i := Length(s1) downto 1 do
      begin
        writeln(s1);
        Dec(s1[0]); { skracanie łańcucha }
      end;
  end.

Na zakończenie tego rozdziału wspomnimy o alternatywnej metodzie reprezentowania danych tekstowych - tak zwanych łańcuchach zakończonych zerem (ang. null-terminated string), zwanych też ASCIIZ. Łańcuch ASCIIZ (podobnie jak string) jest zwykłą tablicą znaków, jednak nie posiada pola przechowującego długość; w zamian za to jego koniec sygnalizowany jest znakiem o kodzie 0 (nie mylić ze znakiem "0"). Efektywna pojemność łańcucha ASCIIZ ograniczona jest wielkością dostępnej pamięci (w praktyce do 64 kB) a więc jest znacznie większa, niż dla typu string.

Łańcuchy ASCIIZ (dostępne począwszy od wersji 7.0 Turbo Pascala) deklarowane są jako zwykłe tablice znaków indeksowane od zera, np.:

  var
    BardzoDlugiLancuch : array[0..10000] of char;

Elementarna obsługa łańcuchów ASCIIZ (wczytywanie, wyprowadzanie, przypisywanie) realizowana jest tak samo, jak dla zwykłych łańcuchów, pod warunkiem włączenia tzw. rozszerzonej składni dyrektywą kompilatora {$X+} (Options-Compiler-Extended Syntax). Bardziej złożone operacje na łańcuchach ASCIIZ (kopiowanie, porównywanie, przeszukiwanie, konwersja do typu string i vice versa) realizowane są przez procedury zawarte w module bibliotecznym Strings (o modułach wkrótce) i nie będą tu omawiane. Warto wreszcie wspomnieć o typie wskaźnikowym PChar, umożliwiającym manipulowanie na dynamicznie tworzonych i usuwanych łańcuchach ASCIIZ.

Ponieważ w większości przypadków typ string znakomicie spełnia swoje zadanie, poprzestaniemy na powyższych wzmiankach, odsyłając zainteresowanych Czytelników do systemu pomocy i literatury [2, 3]. W następnym rozdziale zajmiemy się problemem braku pamięci, czyli wspomnianym przed chwilą dynamicznym tworzeniem i usuwaniem zmiennych

Zapamiętaj

Poprzedni | Spis treści | Następny | Wersja spakowana |