Zadaniem programisty bardzo często jest obsługa zmiennych napisowych (łańcuchów znaków) czyli tzw. stringów. Dzieje się to szczególnie często w przypadku programowania webowego. Zagadnienie zmiennych napisowych w Pythonie jest wbrew pozorom bardzo obszerne. W tym artykule chciałbym skupić się na pokazaniu najpotrzebniejszych operacji związanych ze zmiennymi napisowymi.
Łańcuchy znaków w programowaniu zazwyczaj są zazwyczaj utożsamiane z listą (lub tablicą) pojedynczych znaków. Dzieje się tak dlatego, że w komputerze na bardzo niskim poziomie abstrakcji przechowywane są liczby, a każdy pojedynczy znak można zamienić na liczbę.
O różnych typach danych w Pythonie pisałem już przy okazji pierwszego artykułu z cyklu Nauka Podstaw Pythona, do lektury którego zachęcam Ciebie już teraz 🙂
Dużą literę 'A’ w komputerze przechowujemy jako liczbę 65, gdyż taki jest jej kod ASCII. Aby zamienić znak na kod lub odwrotnie, mamy do dyspozycji funkcje ord oraz char.
>>> chr(65)
'A'
>>> ord('A')
65
>>> ord('a')
97
>>> ord('ż')
380
W Pythonie łańcuchy znaków i znaki są tego samego typu
>>> znak = 'a'
>>> napis = "napis"
>>> print(type(znak) is type(napis))
True
Nie ma tutaj również znaczenia czy użyjemy pojedycznych aspostrofów, cudzysłowia czy nawet 3 cudzysłowów.
Operacje tekstowe
Mimo tego, zmienne napisowe możemy traktować jako listy ze znakami, a co za tym idzie, wykonywać podobne operacje jak na listach.
Cięcie napisów
Jedną z najbardziej przydatnych operacji będzie cięcie list, a w naszym przypadku stringów.
>>> text = "Lorem ipsum"
>>> text[0] # pierwszy znak
'L'
>>> text[-1] # ostatni znak
'm'
>>> text[0:5] # od indeksu 0 (włącznie) do indeksu 5 (wyłącznie)
'Lorem'
>>> text[::2] # co 2 znak, od początku do końca
'Lrmism'
>>> text[::-1] # odwrócenie
'muspi meroL'
>>> text[5:] # od 6 znaku (włącznie) do końca
' ipsum'
Rozdzielanie napisów
Bardzo często będziemy chcieli podzielić jakiś napis. Może być to rozdzielenie wyrazów oddzielonych przecinkiem lub podział tekstu na zdania. Służy do tego metoda split, która jako parametr przyjmuje separator – czyli znak lub ciąg znaków, które rozdzielają interesujące nas fragmenty tekstu.
>>> # wyrazy oddzielone przecinkiem
>>> fruit = "apple,banana,pear"
>>> fruit.split(',')
['apple', 'banana', 'pear']
>>> # wyrazy oddzielone przecinkiem i spacją
>>> fruit = "apple, banana, pear"
>>> fruit.split(',')
['apple', ' banana', ' pear']
Jak widać na powyższym przykładzie separator trzeba określać dokładnie, włącznie ze znakami białymi takimi jak spacje. W innym wypadku znaki te pojawią się w rozdzielonych fragmentach, tak jak powyżej (zwróć uwagę na spacje występujące przed 2 elementami tablicy).
>>> fruit = "apple, banana, pear"
>>> fruit.split(', ')
['apple', 'banana', 'pear']
Możemy wskazać również jak dużo separatorów chcemy brać pod uwagę przy dzieleniu tekstu:
>>> fruit = "apple, banana, pear"
>>> podzial = fruit.split(', ', 1)
>>> podzial
['apple', 'banana, pear']
>>> len(podzial)
2
Łączenie napisów
Wiesz już jak podzielić napis na fragmenty, teraz pokażę Ci jak z kilku napisów bądź znaków stworzyć jeden napis. Pomoże nam w tym metoda join.
>>> fruit = ['apple', 'banana', 'pear']
>>> ''.join(fruit)
'applebananapear'
>>> ', '.join(fruit)
'apple, banana, pear'
Wielkość liter
Jeżeli chcemy zmienić wielkość liter możemy użyć funkcji upper, lower, capitalize, title, swapcase:
>>> text = "kAmil kWaPisz"
>>> text.lower() # tekst małymi literami
'kamil kwapisz'
>>> text.upper() # tekst wielkimi literami
'KAMIL KWAPISZ'
>>> text.capitalize() # pierwsza litera wielka
'Kamil kwapisz'
>>> text.title() # pierwsza litera każdego słowa wielka
'Kamil Kwapisz'
>>> "kamil KWAPISZ".swapcase() # małe litery zamienia na wielkie, wielkie na małe
'KAMIL kwapisz'
Znajdowanie wzorców w tekście
Bardzo często mając do przetworzenia jakiś tekst, interesuje nas czy dany wzorzec występuje w tekście. Do tego możemy użyć operacji in wbudowanej w język:
>>> text = "Lorem ipsum"
>>> print("Lorem" in text)
True
>>> print("inny tekst" in text)
False
Korzystając z powyższej metody mamy informację, że dany ciąg znaków znajduje się w tekście. Jeżeli chcemy dokładniejszej informacji o miejscu, w którym dany fragment się znajduje możemy użyć metod find lub index.
>>> text = "Lorem ipsum"
>>> text.find("rem")
2
>>> text.index("rem")
2
>>> text.find("m")
4
>>> text.find("jakiś napis")
-1
>>> text.index("jakiś napis")
Traceback (most recent call last):
File "<pyshell#85>", line 1, in <module>
text.index("jakiś napis")
ValueError: substring not found
Jak widać na powyższym przykładzie, obie metody działają niemal identycznie. Różnica polega na tym, że metoda index w razie nieznalezienia wzorca w tekście zwraca błąd, a metoda find wartość -1.
W przypadku wystąpienia dwóch lub więcej wzorców zostanie zwrócony indeks pierwszego wystąpienia. Jeżeli wzorców jest więcej, możemy je policzyć metodą count:
>>> text.count('m')
2
Przydatnymi mogą również okazać się metody startswith i endswith, które pozwają określić czy dany napis rozpoczyna się lub kończy daną sekwencją znaków.
>>> url = "http://kamil.kwapisz.pl"
>>> print(url.startswith("http"))
True
>>> print(url.endswith("pl"))
True
>>> print(url.endswith(".com"))
False
Zamiana wzorca
Wiesz już jak znajdować wzorzec, teraz pokażę Ci jak zamienić w tekście znak lub ciąg znaków na inny. Służy do tego metoda replace.
>>> "apple,banana,pear".replace(",", " ")
'apple banana pear'
Jak widać na powyższym przykładzie metoda replace zamieniła wszystkie wystąpienia danego znaku. Można jednak ograniczyć liczbę zamian za pomocą ostatniego parametru:
>>> "apple,banana,pear".replace(",", " ", 1)
'apple banana,pear'
Zamiana również działa dla ciągu znaków:
>>> "apple,banana,pear".replace("pear", "orange")
'apple,banana,orange'
W przypadku braku danego wzorca w tekście zwrócony tekst będzie miał identyczną wartość jak wcześniej, nie zostanie rzucony żaden błąd:
>>> "apple".replace("brak tekstu", "orange")
'apple'
Walidacja napisów
Bardzo często napis przechowywany przez nas zmiennje pochodzi z innych źródeł – na przykład od użytkownika. Chcemy wtedy dokonać walidacji tego ciągu znaków. Do tego możemy wykorzystać kilka mechanizmów wbudowanych w Pythona. Metody te można poznać po nazwie rozpoczynającej się od is-.
Przydatnym sprawdzeniem jest czy dane napisowe są alfranumeryczne(metoda isalnum)
>>> "Złota 44".isalnum() # spacja nie jest znakiem alfanumerycznym
False
>>> "Złota44".isalnum()
True
Możesz również sprawdzić czy ciąg znaków składa się z samych liter (metoda isaplha):
>>> "abc".isalpha()
True
>>> "żółć".isalpha()
True
>>> "Lorem Ipsum".isalpha()
False
>>> "abc12312".isalpha()
False
czy też cyfr (metoda isdigit):
>>> "123".isdigit()
True
>>> "1214.3".isdigit()
False
Do sprawdzenia czy string składa się tylko ze znaków białych (czyli np. spacji, tabów) służy metoda isspace:
>>> " ".isspace()
True
Dostępne są również metody pozwalające sprawdzić wielkość liter:
>>> "tekst".islower()
True
>>> "DUŻE LITERY".isupper()
True
>>> "Kamil Kwapisz".istitle()
True
Usuwanie spacji
Czasem string otrzymany od użytkownika jest otoczony niepotrzebnymi znakami białymi. Służą do tego metody strip.
>>> " tekst".lstrip() # usuwanie znaków białych z lewej strony
'tekst'
>>> "tekst ".rstrip() # usuwanie znaków białych z prawej strony
'tekst'
>>> " tekst ".strip() # usuwanie znaków białych z obu stron
'tekst'
Formatowane napisy
Jedną z najprzydatniejszych funkcji związanych z napisami jest tworzenie formatowanych napisów. Polega to na tworzeniu tekstów z wykorzystaniem wartośći zmiennych w naszym programie.
Jedną z metod jest sklejanie napisów (tzw konkatenacja) za pomocą zwykłego operatora dodawania.
>>> result = 156
>>> "wynik = " + str(result)
'wynik = 156'
W Pythonie ważne, aby wszystkie dodawane elementy były tego samego typu, czyli w tym przypadku napisami.
>>> "wynik = " + 241
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
"wynik = " + 241
TypeError: must be str, not int
Metoda ta jednak nie jest najbardziej użyteczna. Dużo lepiej sprawdza się formatowany string.
W Pythonie jest na to kilka sposób, jednak w najnowszych wersjach preferowane są tzw. f-stringi. Rozpoznasz je po literze f znajdującej się przed cudzysłowiem.
>>> x = 15
>>> text = f"wynik = {x}"
>>> print(text)
wynik = 15
Zmienne w f-stringach umieszczamy w nawiasch klamrowych tak jak widać to na powyższym przykładzie.
W nawiasach klamrowych umieszczać możemy również operacje:
>>> f"wynik = {34 * 15}"
'wynik = 510'
Korzystając z f-stringów możemy również narzucać odpowiedni format liczb:
>>> pi = 3.1415
>>> f"{pi:.3f}"
'3.142'
Liczba zostanie odpowiednio zaokrąglona zgodnie z zasadami matematyki.
Możemy również użyć separatora tysięcznego:
>>> mln = 1000000
>>> f"{mln:,}"
'1,000,000'
Opisane powyżej operacje możliwe są jedynie od wersji 3.6 Pythona. We wcześniejszych wersjach należy skorzystać z metody format.
>>> x = 30
>>> y = 15
>>> "wynik = {}, y = {}".format(x, y)
'wynik = 30, y = 15'
>>> pi = 3.1415
>>> "{:.3f}".format(pi)
'3.142'
>>> mln = 1000000
>>> "{:,}".format(mln)
'1,000,000'
Bloki tekstowe
Czasami chcemy stworzyć zmienną przechowującą dłuższy tekst, składający się z wielu linii, wcięć. Służą do tego bloki tekstowe, które tworzymy za pomocą potrójnych cudzysłowów.
>>> tekst = """
Tekst składający się z wielu linii
wcięć
Zachowane jest
jego formatowanie"""
>>> tekst
'\nTekst składający się z wielu linii\n\twcięć\nZachowane jest\n\njego formatowanie'
>>> print(tekst)
Tekst składający się z wielu linii
wcięć
Zachowane jest
jego formatowanie
Nowa linia i tabulacja
Innym sposobem umieszczania znaków końca linii czy tabulacji jest korzystanie ze znaków specjalnych. Znak nowej linii to (\n), a tabulacji to (\t).
>>> print("Tekst\nw wielu liniach\n\t z tabulacją")
Tekst
w wielu liniach
z tabulacją
jak widać jest to znacznie mniej czytelny sposób niż bloki tekstu.
Znaki specjalne w tekście
Zauważyłeś już pewnie, że w stringach często używa się pewnych znaków ze specjalną funkcją, takich jak apostrofy, cudzysłowia czy ukośniki.
Często jednak znaki te potrzebne są w tekście, który piszemy.
Jeżeli chodzi o używanie cudzysłowów czy apostrofów to sprawa jest prosta. Jeżeli w tekście chcemy użyć cudzysłowów, to string piszemy w apostrofach i odwrotnie.
>>> print('Książka "Zaczynaj od dlaczego" Simona Sinek...')
Książka "Zaczynaj od dlaczego" Simona Sinek...
>>> print("Książka 'Zaczynaj od dlaczego' Simona Sinek...")
Książka 'Zaczynaj od dlaczego' Simona Sinek...
Gdy chcesz użyć apostrofów i cudzysłowów, cały string zamknij w potrójnych apostrofach/cudzysłowach:
>>> print('''Książka "Zaczynaj od dlaczego" Simona Sinek'a...''')
Książka "Zaczynaj od dlaczego" Simona Sinek'a...
Inną metodą jest stosowanie znaku ucieczki czyli ukośnika (/). Znak ten pozbawia inny znak specjalny jego funkcji i pozwala traktować jako zwykły znak.
>>> print("tekst w cudzysłowie: \"tekst\"")
tekst w cudzysłowie: "tekst"
Tak samo można zrobić z ukośnikiem:
>>> print("ukośnik \\ w tekście")
ukośnik \ w tekście
Funkcja print
Skoro opisuję już zmienne napisowe to należy wspomnieć o powiązanej z nimi funkcją print, czyli funkcją do wyświetlania napisu.
Nie trzeba nikomu tłumaczyć podstawowego sposobu jej działania.
>>> print("jakiś tam napis")
jakiś tam napis
Funkcja ta pozwala jednak również na nieco więcej.
Możesz drukować kilka zmiennych obok siebie, nie myśląc nawet o ich typach.
>>> print("tekst", 3.14, True)
tekst 3.14 True
Domyślnym separatorem wartości jest spacja, jednak możemy to zmienić ustawiając wartość parametru sep.
>>> print("tekst", 3.14, True, sep="|")
tekst|3.14|True
Domyślnie każda wydrukowana wartość kończy się znakiem nowej linii. To również możemy zmienić
>>> def drukuj_wynik(wynik):
print("wynik =", end=" ")
print(wynik)
print("tutaj mamy już nową linię")
>>> drukuj_wynik(36)
wynik = 36
tutaj mamy już nową linię
Najczęstym wykorzystaniem tej funkcji jest właśnie drukowanie napisów, które nie kończą się znakiem nowej linii:
>>> print("Tekst", end="")
Tekst
Funkcja print pozwala również zapisywać tekst od razu do pliku. Aby to zrobić musimy ustawić wartość parametru file podając tam zmienną plikową (tzw uchwyt do pliku):
>>> filename = 'test_file.txt'
>>> f = open(filename, "w") # otwieramy plik do zapisu
>>> print("Testowa wiadomość", file=f)
>>> f.close()
>>> f = open(filename, "r") # otwieramy plik do odczytu
>>> f.read()
'Testowa wiadomość\n'
Wyświetlanie struktur danych
Często podczas pracy z bardziej skomplikowanymi danymi jak np zagnieżdżone słowniki (często zdarza się to parsując dane w formacie JSON) chcemy przejrzeć dane wyświetlając je na ekran.
Wyświetlanie ich za pomocą zwykłej funkcji print może nie być zbyt czytelne:
>>> slownik = {
'imie': "Kamil",
'nazwisko': "Kwapisz",
'blog': {
'url': "http://kamil.kwapisz.pl",
'protokół': "HTTP",
'linki': {
'O mnie': 'http://kamil.kwapisz.pl/o-mnie/',
'Kontakt': "http://kamil.kwapisz.pl/kontakt/",
}
}
}
>>> print(slownik)
{'imie': 'Kamil', 'nazwisko': 'Kwapisz', 'blog': {'url': 'http://kamil.kwapisz.pl', 'protokół': 'HTTP', 'linki': {'O mnie': 'http://kamil.kwapisz.pl/o-mnie/', 'Kontakt': 'http://kamil.kwapisz.pl/kontakt/'}}}
Aby wyświetlić to w znacznie przyjemniejszy dla oka sposób możesz użyc biblioteki pprint
>>> pprint(slownik)
{'blog': {'linki': {'Kontakt': 'http://kamil.kwapisz.pl/kontakt/',
'O mnie': 'http://kamil.kwapisz.pl/o-mnie/'},
'protokół': 'HTTP',
'url': 'http://kamil.kwapisz.pl'},
'imie': 'Kamil',
'nazwisko': 'Kwapisz'}
Podsumowanie
W tym artykule pokazałem Ci narzędzia i mechanizmy związane z obsługą zmiennych napisowych w Pythonie.
Wydaje się dużo jak na jeden raz? Być może, jednak chciałem przedstawić Ci pewnego rodzaju kompendium wiedzy z tym związanej.
Jeżeli kiedyś będziesz pracował ze stringami i nie będziesz pamiętał jak wykonać konkretną operację, zawsze możesz wrócić do tego artykułu i przypomnieć sobie potrzebną operację 🙂
Pamiętaj jednak, że to wszystko co przedstawiłem to właściwie wierzchołek góry lodowej. Nie wymieniłem nawet wszystkich mechanizmów związanych z napisami, które są wbudowane w Pythona.
Zabrakło nawet wyrażeń regularnych, jednak nieumieszczenie ich było celowe, gdyż jest to zbyt skomplikowany temat aby umieszczać go w tym artykule.
Nie pisałem także nic o dodatkowych bibliotekach, które ułatwiają pracę ze stringami i poszerzają możliwości na obsługę ich.
Między innymi o takich bibliotekach (np. bibliotece do szerszej walidacji napisów) możesz przeczytać w dokumencie, który dla Ciebie przygotowałem.
Wystarczy, że wejdziesz na stronę główną, klikniesz na okładkę dokumentu i zapiszesz się na newsletter, a otrzymasz link do jego pobrania 🙂
Zachęcam Cię do zapoznania się z nim, gdyż wykorzystanie wylistowanych w nim bibliotek i pakietów naprawdę może usprawnić, i co może nawet ważniejsze, uprzyjemnić Twoją pracę 🙂
Daj znać jak podobał Ci się ten tekst 🙂
Jeśli możesz to napisz w komentarzu o jakich tematach związanych z nauką Pythona chciałbyś przeczytać artykuł 🙂
Pozdrawiam Cię serdecznie! 🙂
Kamil Kwapisz
hej macie jakies darmowe lekcje dla ułomnych osób prosze pomóżcie : ]