Piątek 11 Kwiecień 2025r. Godz 00:00:00      
Postów: 251      

Perl - Obsługa łańcuchów

Obsługa łańcuchów jest jedną z mocnych stron Perla. Oferuje on duże możliwości w tej dziedzinie. Na początek podam sposób sprawdzania, czy dane wyrażenie występuje czy też nie występuje w przeszukiwanym łańcuchu:

$s =~ /Ala/     # wyrażenie to zwróci wartość
                # prawda, jeżeli okaże się, że
                # łańcuch $s zawiera szukane
                # słowo zawarte w pochyłym
                # nawiasie
$s !~ /Ala/     # wyrażenie to zwróci wartość
                # prawda, jeżeli okaże się, że
                # łańcuch $s nie zawiera
                # szukanego słowa zawartego
                # w pochyłym nawiasie

Nadażyła się dobra okazja, aby przedstawić zmienną $_, która jest domyślną zmienną i na której operuje wiele funkcji wtedy, gdy inna zmienna nie została do konkretnego celu wyszczególniona. Takie rozwiązanie skraca nieco kod oraz eliminuje zbyt dużą liczbę zmiennych i mogące z tego wyniknąć zamieszanie.

$s = 'Ala ma kota.';
if ($s =~ /Ala/)
{
  print 'Odnaleziono wyraz Ala!';
}

Powyższy zapis jest równoważny następującemu:

$_ = 'Ala ma kota.';
if (/Ala/)
{
  print 'Odnaleziono wyraz Ala!';
}

Kiedy poszukujemy w danym łańcuchu konkretnego zapisu, korzystamy często z wielu znaków o specjalnym znaczeniu, umieszczanych wewnątrz pochyłego nawiasu. Te znaki to:

.       # jakikolwiek znak oprócz znaku
        # nowej linii (n)
^       # rozpoczęcie nowej linii lub
        # łańcucha
$       # koniec linii lub łańcucha

*       # dowolna ilość powtórzeń
        # ostatniego znaku
+       # jedno lub więcej powtórzeń
        # ostatniego znaku
?       # brak lub jedno wystąpienie
        # ostatniego znaku

Za pomocą powyższych znaków specjalnych można budować maski i porównywać je ze zmiennymi. Oto kilka przykładowych masek:

.*        # łańcuch składający się z dowolnych
          # znaków oprócz znaków końca linii
^$        # pusta linia
.*x$      # dowolny ciąg znaków, który kończy
          # się literą "x"

Zwykłych nawiasów możemy używać do grupowania znaków:

(.*)*     # dowolna ilość dowolnych łańcuchów
(^$)+     # jedna lub więcej pustych linii
(.*x$)*   # dowolna ilość łańcuchów
          # zakończonych literą "x"

Jeśli chcemy odnaleźć którykolwiek znak spośród kilku, należy je umieścić w nawiasach kwadratowych. I tak:

[abc]     # którykolwiek ze znaków: a, b lub c
[^abc]    # negacja: ani a ani b ani c
[a-z]     # jakiekolwiek znaki od a do z
[^a-z]    # jakiekolwiek znaki oprócz
          # znaków od a do z

Nawiasy klamrowe służą do określania ilości powtórzeń wystąpienia łańcucha:

(.*){3}         # trzy dowolne
                # łańcuchy
(^$){3,}        # przynajmniej trzy dowolne
                # łańcuchy
(.*x$){3,5}     # przynajmniej trzy, ale nie
                # więcej niż pięć łańcuchów
                # zakończonych literą "x"

Aby w masce zawrzeć znaki, które mają pierwotnie swoje znaczenie w języku (np. $) należy je poprzedzić znakiem "". Na przykład:

^
$
*

Ponadto w masce niektóre litery poprzedzone znakiem "" nabierają specjalnego znaczenia:

n      # znak nowej linii
t      # tabulator
a      # alarm

l      # następny znak ma być małą literą
u      # następny znak ma być dużą literą
L      # następne znaki mają być małymi
        # literami, aż do wystąpienia E
U      # następne znaki mają być dużymi
        # literami, aż do wystąpienia E

w      # pojedynczy znak alfanumeryczny
W      # jakikolwiek znak nie będący
        # znakiem alfanumerycznym
s      # spacja
S      # jakikolwiek znak, który nie
        # jest spacją
d      # liczba
D      # jakikolwiek znak, który nie
        # jest liczbą

Na przykładzie pokażę sposób "wyłuskiwania" pewnych części łańcuchów za pomocą porównywania ich z maskami:

$_ = 'linux Operating system';
/([A-Z][a-z]+s)+/;  # wykorzystanie
                     # właściwości zmiennej $_

Po wykonaniu takiej czynności do naszej dyspozycji zostaje oddany szereg pseudo-zmiennych, których wartości można jedynie czytać, ale nie zapisywać. Jak widać maska, której użyliśmy, opisuje słowo "Operating". Z tego względu w zmiennej $& odnajdziemy to słowo. Pod zmienną $` natomiast zapisane zostanie słowo "linux", a pod $' słowo "system". Dzięki temu mechanizmowi jesteśmy w stanie "wyłuskać" potrzebną nam część łańcucha.

Przy przeszukiwaniu łańcuchów wszystkie odnalezione wyrażenia zawarte w zwykłych nawiasach są zapamiętywane w pseudo-zmiennych $1, $2, $3, itd. Można je także wykorzystać w ramach aktualnie wykonywanej funkcji odwołując się do nich poprzez 1, 2, 3, itd.

$_ = 'Linux Operating System';
if (/(.*ux)/)
{
  print "$1n";  # znaleziony łańcuch "Linux"
}

Bardzo pomocną funkcją wykorzystującą maski jest s///. Służy ona do podmieniania zawartości jednego wyrażenia innym.

s/linux/Linux/    # przeszukiwany jest łańcuch
                  # $_, a gdy okaże się, że
                  # zawiera on wyrażenie
                  # "linux", zostanie ono
                  # podmienione na łańcuch
                  # "Linux"
s/linux/Linux/g   # przeszukiwany jest łańcuch
                  # $_ i wszystkie wystąpienia
                  # wyrażenia "linux" zostaną
                  # podmienione na łańcuch
                  # "Linux"
s/linux/Linux/gi  # przeszukiwany jest łańcuch
                  # $_ i wszystkie wystąpienia
                  # wyrażenia "linux"
                  # (niezależnie od wielkości
                  # poszczególnych liter)
                  # zostaną podmienione na
                  # łańcuch "Linux"

Przykład zastosowania funkcji s///:

$_ = 'Linux Operating System';
s/([A-Z])/:1:/g;    # każda pojawiająca
                     # się wielka litera
                     # zostanie zawarta
                     # w dwukropkach

Do podmieniania znaków innymi znakami służy funkcja tr///. Na przykład:

$_ = 'LinuX';
tr/A-Z/a-z/;   # podmienienie wszystkich
               # dużych liter na małe

$_ = 'linux';
tr/x/s/;       # podmienienie litery "x" na "s"

Przydatną funkcją w Perlu jest split. Pozwala ona na rozbicie łańcucha i umieszczenie poszczególnych jego części w tablicy:

$s = 'kazik:tomek:marek';
@tab = split(/:/, $s);

Po wykonaniu takiej operacji otrzymamy poszczególne części łańcucha, które w $s były odgraniczane znakiem dwukropka, zapisane w kolejnych polach tablicy. Efekt działania funkcji split będzie wyglądał tak:

@tab = ("kazik", "tomek", "marek");

Oczywiście w miejsce pojedynczego znaku dwukropka możemy wprowadzić dowolne maski, które będą opisywać wyrażenia oddzielające od siebie szukane łańcuchy.

Funkcja split może także być stosowana w krótszej postaci (operować na zmiennej $_):

$_ = 'Linux, Operating System';
@tab = split(/.*s/);

W efekcie otrzymamy tablicę @tab składającą się z trzech wyrazów ("Linux", "Operating", "System") zapamiętanych w kolejnych jej polach.

Funkcja substr pozwala na "wycinanie" części łańcucha. Posługując się nią podajemy miejsce, w którym rozpoczyna się szukany wycinek łańcucha i ewentualnie długość tego wycinka.

$s = substr('Ala ma kota', 2, 6);
               ^    ^
         # łańcuch $s będzie zawierał "a ma k"
$s = substr('Ala ma kota', 6);
                    ^
         # łańcuch $s będzie zawierał "kota"
$s = substr('Ala ma kota', -4, 3);
                    ^ ^
         # łańcuch $s będzie zawierał "kot"