|
Obsługa
ciśgów tekstowych |
|
|
|
|
Wyrażenia regularne
PHP obsługuje 2 rodzaje wyrażeń regularnych:
zgodne ze standardem POSIX (które tu skrótowo opiszę) i te zastosowane w
języku Perl (opis tych wyrażeń zostanie tu umieszczony w terminie
późniejszym). Wyrażenia regularne są to ciągi znaków, które można dopasować
do różnych innych ciągów. Można to porównać do tzw. wildcardów używanych
przy operacjach na plikach, gdzie gwiazdka ('*') zastępowała dowolną ilość
dowolnych znaków, czyli wyrażenie '*.*' (w przypadku systemów dosowych)
będzie pasowało do plików o dowolnej nazwie i dowolnym rozszerzeniu.
Wyrażenia regularne są o wiele bardziej skomplikowane i też działają trochę
inaczej. W wildcardach gwiazdka zastępowała dowolną ilość dowolnych znaków,
natomiast w wyrażeniach regularnych działa niejako 'wstecz' - opisuje
dowolną ilośc powtórzeń (zero lub więcej) poprzedniego znaku, czyli
wyrażenie 'a*' będzie pasowało do 'aaa', 'aaaaa' ale i 'b', ponieważ w tym
wyrażeniu nie ma ograniczenia że nie może być nic oprócz 'a'. Takie
ograniczenie można uzyskać dzięki znakom '^' i '$'. Znak '^' rozumiany jest
jako początek linii, a '$' jako koniec. Tak więc jeśli chcemy znaleźć ciąg,
który będzie pusty lub będą w nim same litery 'a', to powinien on wyglądać
tak: '^a*$'. Natomiast jeśli 'a' musi wystąpić przynajmniej raz, to zamiast
znaku '*' należy użyć znaku '+' - oznacza on jedno lub więcej powtórzeń
ostatniego znaku. Istnieje też możliwość użycia znaku '?', który oznacza
żadne lub jedno wystąpienie poprzedzającego ten znak atomu, znaku lub
zakresu. Można także podać konkretną ilość wystąień znaku, atomu lub
przedziału przez użycie za raz po nich nawiasów klamrowych. Jeśli będzie w
nich jedna liczba, to będzie ona określała dokładnie daną liczbę powtórzeń.
Jeśli będzie w nich liczba a po niej przecinek, to wyrażenie będzie musiało
wystąpić przynajmniej tyle razy ile wynosi podana liczba. Istnieje także
możliwość podania w nawiasach klamrowych dwóch liczb oddzielonych
przecinkiem, co oznacza powtórzenie wyrażenia minimalnie tyle razy ile
pierwsza liczba, a maksymalnie tyle ile druga (włącznie).
Zamiast pojedyńczego znaku można podać zakres wyrazów lub całe wyrażenie -
tzw. atom. Zakres znaków podaje się w nawiasach kwadratowych. W tych
nawiasach można podać pojedyńcze znaki jeden po drugim (np. '[egt]'),
przedział liter (np. wszystkie małe litery: '[a-z]' - uwaga, zakres ten nie
obejmuje polskich znaków diakratycznych), lub połączenie tych dwóch typów (np.
'[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]' określa wszystkie litery). W nawiasach
kwadratowych można podawać także symbole. Jeśli w przedziale potrzebny jest
znak myślnika, który normalnie używany jest do określania przedziałów znaków,
to trzeba umieścić go na pierwszej lub ostatniej pozycji w nawiasach
kwadratowych. W nawiasach kwadratowych znak '^' ma inne znaczenie. Oznacza
ono zaprzeczenie, czyli jeśli umieści się je przed znakiem lub zakresem, to
ten znak lub zakres nie będzie mógł się pojawić w tym miejscu.
Jeśli znak może być dowolny, to zamiast konkretnej litery, znaku czy
przedziału można użyć symbolu kropki ('.'). Przykładowo wyrażenie '^.*$'
opisuje dowolny ciąg składający się z dowolnej ilości dowolnych znaków.
Atom, czyli wyrażenie zawarte w nawiasach okrągłych, może zawierać (prawie)
dowolną ilość znaków, zakresów i innych atomów. Pozwala to na dopasowywanie
powtarzających się fragmentów ciągów znaków. Dobrym przykładem jest
sprawdzenie, czy dany ciąg znaków jest ścieżką w systemie uniksowy.
Przykładowy ciąg to '/usr/local/bin/php'. Wyrażenie regularne powinno
wyglądać tak: '(/([a-Z])+)*(/([a-Z\.]))'. Pierwszy atom określa dowolną
ilość katalogów (na początku znak slash a po nim dowolna ilość liter o
dowolnej wielkości) po czym nazwa pliku - po atomie nie ma żadnego znaku
określającego ilość wystąpień, a więc musi wystąpić dokładnie raz.
Pomiędzy atomami, znakami lub zakresami można postawić znak '|', który
oznacza logiczną operację 'OR', czyli poprostu oznacza że może wystąpić
jeden lub drugi atom (ten przed znakiem '|' i ten po).
Jeśli w wyrażeniu regularnym musisz podać znak, który byłby interpretowany
inaczej niż zamierzamy (np. jeśli musisz znaleźć ciąg zaczynający się od
gwiazdki po której jest dowolna ilość liter A, to nie można 'normalnie'
podać znaku gwiazdki, ponieważ byłby on interpretowany jako dowolna ilość
powtórzeń ostatniego znaku), to należy zamienić ten znak na tzw. 'escape
sequence' - poprostu należy przed tym znakiem wstawić znak ukośnika ('\').
Takie znaki to: '(', ')', '[', ']', '{', '}', '\', '*', '|', '^', '$', '?'.
Jeśli w wyrażeniu trzeba użyć właśnie znaku ukośnika, to należy wpisać dwa
ukośniki, jeden po drugim.
Porównywanie ciągów
Podstawową funkcją służącą do porównywania ciągów jest strcmp(). Jako jedyne
2 parametry przyjmuje ona ciągi tekstowe, które mają być porównane. Funkcja
ta zwraca wartość 0 jeśli ciągi są takie same, wartość większą od zera jeśli
pierwszy ciąg jest większy od drugiego lub wartość mniejszą od zera jeśli
pierwszy ciąg jest mniejszy od drugiega. Funkcja ta rozróżnia wielkość
znaków. Jeśli zachodzi potrzeba porównania dwóch ciągów, to należy użyć
funkcji strcasecmp() (parametry i wartości zwracane takie jak przy funkcji
strcmp). Istnieje także funkcja strncmp(), która porównuje tylko taką ilość
początkowych znaków z podanych ciągów, jaka została podana jako trzeci
parametr tej funkcji. Oczywiście istnieje też wersja funkcji strncmp()
ignorująca wielkość znaków: strncasecmp().
Istnieje racjonalne wytłumaczenie dlaczego ciągi należy porównywać za pomocą
funkcji strcmp() lub pochodnych a nie zwykłego operatora porównania '=='.
Interpreter języka PHP stara się być mądrzejszy od programisty automatycznie
konwertując typy zmiennych aby przy porównywaniu ich były takie same. Tak
więc warunek:
<?
$a=0;
$b="0papa";
if($a==$b)
echo "Tak";
else
echo "Nie";
?>
wyświetli "Tak", pomimo że te zmienne są różne. Dlaczego? Ponieważ PHP
automatycznie konwertuje zmienną $b do typu liczbowego, przez co zamieniana
jest ona na liczbową wartość 0 (która faktycznie jest na pierwszym miejscu
ciągu - pozostałe znaki są odrzucane ponieważ nie są liczbami). Można
teoretycznie użyć operatora "===" - porównania nie tylko wartości, ale też
typu, ale tu z kolei warunek:
<?
$a=0;
$b="0";
if($a===$b)
echo "Tak";
else
echo "Nie";
?>
wyświetli nie, bo pomimo że obie zmienne mają wartość 0, to zmienna $a jest
liczbą, a zmienna $b ciągiem tekstowym.
Funkcja strstr() służy do sprawdzania, czy podany ciąg jest fragmentem
innego ciągu. Funkcja przyjmuje dwa parametry: przeszukiwany ciąg ('stóg
siana') i szukany ciąg ('igła'). Jeśli dany ciąg jest fragmentem podanego,
to zwracany jest ciąg - fragment przeszukiwanego ciągu od pierwszego
wystąpienia szukanego ciągu do końca. Np.:
<?
$email = "prezydent@polska.pl";
$domena = strstr($email, "@");
echo $domena;
?>
wyświetli "@polska.pl". Jeśli ciąg nie jest znaleziony, to zwracana jest
wartość FALSE, dzięki czemu funkcję tą można używać w instrukcjach
warunkowych, np.:
<?
$email = "prezydent@polska.pl";
if(strstr($email, "polska")!==False)
echo "Email ma w sobie słowo 'polska'";
?>
Przy używaniu tej funkcji trzeba pamiętać o jednej rzeczy. Łatwo jest
pomylić zwracaną wartość 'znaleziono na pozycji 0' i 'nie znaleziono',
ponieważ wartość logiczna 'true' przy porównaniach może być skonwertowana do
wartości liczbowej 0. Aby tego uniknąć należy używać operatora porównania ze
sprawdzaniem typu ('===' lub '!==').
Istnieje także wersja tej funkcji ignorująca wielkość znaków:
stristr()(przyjmowane parametry i zwracane wartości takie jak przy funcji
strstr).
Pomimo, że funkcji strstr() można używać do sprawdzania czy jeden ciąg jest
częścią drugiego, to jest ona nieefektywna. Lepiej skorzystać z funkcji
strpos().
Do sprawdzania, czy ciąg tekstowy pasuje do wyrażenia regularnego używa się
funkcji ereg która jako pierwszy parametr przyjmuje wyrażenie regularne, a
jako drugi ciąg który ma być porównany z wyrażeniem. Istnieje także wersja
tej funkcji ignorująca wielkość znaków: eregi. Zwracana jest wartość true
jeśli ciąg pasuje do wyrażenia regularnego, a false jeśli nie pasuje.
Zazwyczaj przy instrukcjach warunkowych w którch korzysta się z funkcji
sprawdzającej jakiś warunek, funkcja ta zwraca wartość TRUE jeśli warunek
jest spełniony, np. funkcja ereg zwraca tą wartość jeśli dany ciąg pasuje do
danego wyrażenia regularnego. W takim przypadku instrukcję warunkową można
zapisać tak:
<?
if(ereg(".*", $ciag))
echo "Znalazłem!";
?>
Natomiast w przypadku funkcji strcmp() i pochodnych jest trochę inaczej,
gdyż jeśli ciągi są identyczne to zwracana jest wartość 0 uznawana za
logiczne FALSE. A więc instrukcja warunkowa porównująca ciągi może wyglądać
tak:
<?
if(!strcmp("cośtam", $string))
echo "$string to cośtam!";
?>
Wyciąganie fragmentów ciągów
Bardzo często zachodzi potrzeba wyciągnięcia ze zmiennej tekstowej tylko
pewnego jej fragmentu. Najłatwiej jest jeśli znana jest długość wyciąganego
fragmentu i pozycja w której się znajduje w zmiennej. Np. jeśli ze zmiennej
zawieracjącej "1992/11/19" chcemy wyciągnąć rok. Wiadomo, że rok jest na
samym początku i ma 4 znaki. Najłatwiej jest użyć funkcji substr(). Jako
pierwszy paramter pobiera ona ciąg z którego będzie wycinany fragment, jako
drugi miejsce, z którego będzie rozpoczęte wycinanie (0 jeśli od pierwszego
znaku, liczba ujemna jeśli ma to być ilość znaków od końca), a ostatni,
opcjonalny parametr wskazuje ilość znaków do wycięcia (jeśli pominie się ten
parametr, to zwrócony zostanie pod-ciąg od wskazanego znaku początkowego do
końca ciągu). A więc tym przypadku wywołanie funkcji substr() będzie
wyglądało tak:
<?
$data = "1992/11/19";
$rok = substr($data, 0, 4);
?>
Ale to oczywiście najprostsza z sytuacji. Bardziej skomplikowanym przykładem
będzie wyciągnięcie z tej samej daty wszystkich pól. Można oczywiście 3 razy
używać funkcję substr, ale wydajniejszą metodą jest rozbicie tekstu na
tablicę korzystając z opisanej przy okazji tablic funkcji explode. Tak więc
po takim fragmencie kodu:
<?
$data = "1992/11/19";
$tablica = explode("/", $data);
?>
w pierwszym elemencie tablicy znajdować się będzie rok, w drugim a w trzecim
dzień z podanej daty. Można także użyć tej funkcji w bardziej skomplikowany
sposób - do rozbicia ciągu zawierającego datę i czas:
<?
$tekst = "19/11/1982 01:43:12";
$dataiczas = explode(" ", $tekst);
$data = explode("/", $dataiczas[0]);
$czas = explode(":", $dataiczas[1]);
?>
Teraz tablica $data zawiera dzień, miesiąc i rok a tablica $czas godzinę,
minutę i sekundę. Ale co jeśli godzina zawiera setne części sekundy, które
podawane są po kropce? Robić jeszcze jedno rozbicie? To już za dużo. Lepiej
jest użyć funkcję split(), która funcjonuje w podobny sposób co explode, ale
rozbija tekst nie za pomocą zwykłych ciągów znaków, ale za pomocą wyrażeń
regularnych. Tak więc cały string zawierający datę i czas (z setnymi
sekundami włącznie) można rozbić za pomocą jednego wywołania funkcji
split():
<?
$tekst = "19/11/1982 01:43:12.10";
$tablica = split("[ /:.]", $tekst);
?>
Teraz w tablicy $tablica znajować się będą po kolei: dzień, miesiąc, rok,
godzina, minuta, sekunda i setna część sekundy.
Może też zajść potrzeba wyciągnięcia fragmentu ciągu do jakiegoś znaku, np.
pierwszego zdania z jakiegoś tekstu. Wtedy można użyć połączenia funkcji
substr() i strpos(), która zwraca numer znaku gdzie znajduje się pierwsze
wystąpienie ciągu podanego jako drugi parametr w ciągu podanym jako pierwszy
parametr, lub false jeśli pierwszy ciąg nie zawiera w sobie drugiego. A więc
pierwsze zdanie podanego ciągu można uzyskać tak:
<?
$tekst = "To jest tekst. Tego zdania nie będzie widać.";
$zdanie = substr($tekst, 0, strpos($tekst, "."));
?>
Zmienna $zdanie powinna zawierać "To jest tekst" - bez kropki na końcu.
Podmienianie fragmentów ciągów
Do podmiany całych fragmentów ciągu służy funkcja str_replace(), która
przyjmuje 3 parametry: ciąg który ma być podmieniony, ciąg na który ma być
podmieniony i ciąg którego fragmenty będą podmieniane. A więc wszystkie
wystąpienia pierwszego ciągu w trzecim ciągu są zamieniane na drugi ciąg.
UWAGA: zmienna podawana jako trzeci parametr nie jest zmieniana. Poprawiony
ciąg jest zwracany przez funkcję. Przykład:
<?
$tekst = "Jeśli jesteś za podnieś rękę";
$wynik = str_replace("za", "przeciw", $tekst);
?>
Zmienna $wynik będzie zawierała tekst "Jeśli jesteś przeciw podnieś rękę".
Od wersji PHP 4.0.5 każdy z parametrów funkcji str_replace może być tablicą.
A więc jeśli trzeci parametr jest tablicą, to operacja podmany tekstów jest
wykonywana jest na każdym elemencie tablicy, a zwracana zmienna także jest
tablicą. Natomiast jeśli tablicami są pierwszy i drugi parametr, to każdy
element z pierwszej tablicy jest podmieniany na odpowiadający mu element
drugiej tablicy. Jeśli pierwsza tablica ma więcej elementów niż druga, to te
elementy z pierwszej tablicy które nie mają odpowiednika w drugiej
zamieniane są na puste ciągi. Pozwala to na wiele podmian za jednym
wywołaniem funkcji str_replace.
Podmienianie znaków w ciągach
W PHP można także znaleźć funkcję, która zamieni wszystkie wystąpienia
podanych znaków na inne znaki. Dzięki temu można np. usunąć wszystkie
polskie znaki diakratyczne albo skonwertować te znaki na inną stronę kodową.
Funkcja ta nazywa się strtr i przyjmuje 3 parametry: ciąg w którym będą
podmieniane znaki, ciąg zawierający znaki do podmiany i ciąg zawierający
znaki, na które te podane w drugim parametrze będą podmienione. W tym
przykładzie polskie znaki diakratyczne zostaną zamieniane na odpowiadające
im
Inne funkcje
htmlspecialchars($string) - funkcja ta zamienia znaki używane w kodzie HTML
na takie, które zostaną wyświetlone prawidłowo, a nie będą interpretowane
przez przeglądarkę jako znacznik HTML. Wszystkie wystąpienia znaku < zostają
zamienione na znak < a znaku > na >. Funkcja ta jest bardzo przydatna
gdy zachodzi potrzeba wyświetlenia kodu źródłowego HTML, który nie powinien
być interpretowany przez przeglądarkę.
htmlentities($string) - jest to rozszerzona wersja funkcji htmlspecialchars().
Zamienia wszystkie znaki na odpowiadające im kody HTML, jeśli takowe
istnieją. Np. wszystkie wystąpienia znaku ó zamieniane są na ó.
chop($string), trim($string), trim($string), rtrim($string) - funkcje te
mają za zadanie usunięcie 'białych znaków' (spacja, tabulator, znacznik
nowego wiersza) z początku lub końca ciągu. Funkcja chop(), tak jak i rtrim(),
usuwa te znaki z końca ciągu, ltrim() z początku a trim() i z początku i
końca.
nl2br($string) - bardzo przydatna funkcja służąca do zamiany znaków końca
wiersza na HTML'owe znaczniki <br> (bardzo przydatne przy wyświetlaniu
sformatowanego tekstu w oknie przeglądarki).
strip_tags($string) - usuwa wszystkie znaczniki HTML z podanego jako
parametr ciągu. Możliwe jest podanie opcjonalnego drugiego parametru - ciągu,
który zawiera nazwy znaczników HTML, które mają zostać pozostawione.
|
|
|
|