Poprzednio poznaliśmy sporo zastosowań listy i możliwości pracy z listą. Teraz pochylmy się nad innym typem danych, jakim jest napis. Istnieje wiele operacji, jakie można wykonywać na tekście. Poznajmy podstawowe z nich.
Test na obecność w napisie – in, count
Aby sprawdzić, czy coś jest elementem napisu możemy użyć po prostu słówka kluczowego in, będącego elementem Pythona. Oto taki test:
msg = "hello world"
print("world" in msg)
#True
Możemy też go użyć w warunku, każdą rzecz, którą da się zredukować do typu prawda/fałsz można użyć jako warunek:
msg = "hello world"
if "world" in msg:
print("world is in msg")
#world is in msg
Możemy też użyć count:
msg = "hello world"
if msg.count("world") > 0:
print("world is in msg")
#world is in msg
Funkcja count zlicza nam ilość wystąpień dla „world”, która jest równa 1 tutaj, zaś warunek daliśmy, aby ta ilość była większa niż 0. Ale wartości 0 i nie-zero też podlegają konwersji, zero do fałszu, nie-zero do prawdy, więc można to tak zapisać:
msg = "hello world"
if msg.count("world"):
print("world is in msg")
#world is in msg
Zawsze, gdy count zwróci coś innego niż 0 nasz warunek będzie prawdziwy, a zawsze, gdy dostaniemy 0 to znak, że naszego elementu w tekście nie ma.
Testy na obecność – startswith, endswith, indeksy
Możemy sprawdzić, czy coś zaczyna się lub kończy w określony sposób. Służą do tego odpowiednie funkcje i mogą one sprawdzać zarówno jeden znak jak i dłuższy tekst:
msg = "Hello World!"
print(msg.startswith("H"))
print(msg.endswith("!"))
print(msg.startswith("Hello"))
print(msg.endswith("World!"))
# True
# True
# True
# True
Jeżeli natomiast chcemy w prosty sposób sprawdzić czy tekst zaczyna się na określoną literę bądź nią kończy, możemy użyć indeksów. Pierwszy znak to zawsze indeks 0 zaś ostatni to -1:
msg = "Hello World!"
print(msg[0] == "H")
print(msg[-1] == "!")
# True
# True
Inne testy – wielkość liter, rodzaj znaku
Możemy sprawdzić, czy coś jest wielką bądź małą literą. Służą do tego funkcje islower() oraz isupper(). Wykonajmy je na pierwszym znaku danego napisu:
msg = "Hello World!"
print(msg[0].islower())
print(msg[0].isupper())
# False
# True
Funkcja index pozwoli nam zobaczyć indeks pierwszego wystąpienia danego znaku lub napisu:
msg = "Hello World!"
print(msg.index("Hello"))
print(msg.index(" "))
# 0
# 5
Fajnie. Widzimy, że pierwsze „Hello” to indeks 0, zaś pierwsza spacja to indeks 5. Teraz, jak już znamy indeks spacji (policzyć go sobie na palcach też mogliśmy) sprawdźmy, czy element o indeksie 5 jest spacją:
msg = "Hello World!"
print(msg[0].isspace())
print(msg[5].isspace())
# False
# True
Pierwszy element spacją nie jest, ale ten o indeksie 5 jak najbardziej. Funkcja isspace służy do wykrywania spacji. Teraz zobaczmy kilka innych funkcji testujących:
msg = "Hello World!"
print(msg[-1].isalpha())
print(msg[-1].isalnum())
# False
# False
print("1".isalpha())
print("1".isalnum())
print("1".isdigit())
# False
# True
# True
Element ostatni nie jest ani literą ani znakiem alfanumerycznym (litery + cyfry). Dla porównania – „1” nie przechodzi testu na literę, przechodzi test na znak alfanumeryczny (litery + cyfry) oraz na bycie cyfrą.
Zamiana w tekście – replace
W tekście możemy coś zamienić korzystając z replace. Oto przykład zamiany spacji na znak '|’
msg = "Hello World!"
msg = msg.replace(" ", "|")
print(msg)
#Hello|World!
Warto zwrócić uwagę, że tekst jest niemutowalnym typem, a zatem msg.replace zwraca nam kopię tego tekstu z odpowiednią „podmianką”. Tę kopię przypisujemy do naszej zmiennej. Taki drobny szczegół.
Odwrócenie tekstu – reversed, [::-1]
Tekst można odwracać na dwa sposoby. Pierwszy to [::-1]:
msg = "Hello World!"
msgrev = msg[::-1]
print(msgrev)
#!dlroW olleH
Drugi to zastosowanie reversed, aczkolwiek pomęczyć się trzeba, aby obiekt reversed zamienić na napis:
msg = "Hello World!"
msgrev = "".join(reversed(msg))
print(msgrev)
#!dlroW olleH
Możemy też po reversed iterować i dodawać element po elemencie:
msg = "Hello World!"
msgrev = ""
for char in reversed(msg):
msgrev += char
print(msgrev)
#!dlroW olleH
Zamiana wielkości liter – upper, lower, swapcase
Funkcja upper podnosi do wielkiej litery, lower – do małej, swapcase – wielką zamienia na małą i odwrotnie:
print("anna".upper())
print("ANNA".lower())
print("aNNA".swapcase())
# ANNA
# anna
# Anna
Usuwanie niepotrzebnych spacji – strip, lstrip, rstrip
Strip usuwa niepotrzebne spacje, czyli takie, które znajdują się przed tekstem, po jego lewej stronie i po tekście, po jego prawej stronie:
msg =" Hello World "
print(msg.strip())
#Hello World
Istnieje też lstrip, który usuwa spacje tylko po lewej i rstrip – tylko po prawej:
msg =" Hello World "
print(msg.strip())
print(msg.lstrip())
print(msg.rstrip())
#Hello World
#Hello World
# Hello World
Zamiana znaku na jego wartość liczbową – ord
Patrząc na klawiaturę, wydawać by się mogło, że komputer gdzieś tam w środku przechowuje litery. Nie jest to jednak prawda, każda litera posiada swoją wartość liczbową. Możemy podejrzeć tę wartość używając funkcji ord:
msg = "Hello world"
for char in msg:
print(ord(char))
# 72
# 101
# 108
# 108
# 111
# 32
# 119
# 111
# 114
# 108
# 100
Jak widać każdy znak ma swoją wartość liczbową. Wielkie litery to dwucyfrowa wartość (H to 72), małe to już liczby powyżej 100, zaś spacja (znak jak każdy inny) to 32. Tak widzi nasze znaki komputer.
Możemy to jeszcze bardziej przesunąć i pokazać każdą literę w zapisie binarnym, wrzucając liczbę z ord do funkcji bin, która liczbę dziesiętną zamienia na binarną:
msg = "Hello world"
for char in msg:
print(bin(ord(char)))
# 0b1100101
# 0b1101100
# 0b1101100
# 0b1101111
# 0b100000
# 0b1110111
# 0b1101111
# 0b1110010
# 0b1101100
# 0b1100100
I tak mniej więcej (minus przedrostek 0b sygnalizujący nam system dwójkowy/binarny) widzi ten nasz napis komputer. Ciekawe, prawda?
Zadanie 1 – zamień tekst na reprezentację liczbową
Tutaj chcemy napisać funkcję, która bierze tekst i wyświetla nam, jakie liczby ten tekst tworzą, jak to widzi komputer. Zabierzmy się do tego. Próba pierwsza:
msg = "Hello World"
lst = [ord(char) for char in msg]
print(lst)
#[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
Mamy skrypt, który zamienia nam każdy znak z tekstu na jego liczbową wartość i pakuje do listy. Jeżeli w takiej formie chcemy zwrócić dane użytkownikowi to w zasadzie mamy wszystko. Jeżeli jednak chcemy mieć napis, to musimy każdy element zamienić na napis:
msg = "Hello World"
lst = [str(ord(char)) for char in msg]
print(lst)
#['72', '101', '108', '108', '111', '32', '87', '111', '114', '108', '100']
Niby różnicy nie ma wielkiej, ale teraz możemy za pomocą join zrobić napis zawierający te liczby:
msg = "Hello World"
lst = [str(ord(char)) for char in msg]
print(lst)
#['72', '101', '108', '108', '111', '32', '87', '111', '114', '108', '100']
print(" ".join(lst))
#72 101 108 108 111 32 87 111 114 108 100
Kleimy po spacji, liczby mają różną długość, więc musi być jakiś znak, który nam mówi, gdzie kończy się 72 a zaczyna 101… Tutaj użyliśmy spacji.
Teraz możemy naszą funkcję napisać. Wersja zwracająca listę:
def text_in_numbers(text):
return [ord(char) for char in text]
print(text_in_numbers("Hello world"))
#[72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
Wersja zwracająca napis:
def text_in_numbers(text):
numbers = [str(ord(char)) for char in text]
return " ".join(numbers)
print(text_in_numbers("Hello world"))
#72 101 108 108 111 32 119 111 114 108 100
Zadanie 2 – napisz własny lstrip
Musimy napisać funkcję, która robi lstrip, czyli usuwa niepotrzebne spacje z lewej strony. Powinniśmy umieć to zrobić.
def my_lstrip(text):
idx = 0
while text[idx] == " ":
idx += 1
return text[idx:]
print(my_lstrip(" hello!"))
#hello!
print(my_lstrip("hello!"))
#hello!
Ta funkcja bierze tekst. Zmienną idx ustawia na zero. Następnie tak długo jak text[idx] jest spacją, zwiększa idx o 1. W pewnym momencie dojdzie to znaku spacją niebędącego i warunek przestanie być prawdziwy.
Ale zostanie nam indeks, gdzie po lewej stronie kończą się spacje. Możemy zatem zwrócić tekst od tego indeksu do końca i to właśnie robimy.
Możemy też napisać własny rstrip. Podobnie zadziała:
def my_rstrip(text):
idx = len(text)-1
while text[idx] == " ":
idx -= 1
return text[:idx+1]
print(my_rstrip("hello! "))
#hello!
print(my_rstrip("hello!"))
#hello!
Tutaj aby „dobrać się” do ostatniego indeksu musimy od długości tekstu odjąć 1. Następnie idziemy do tyłu (od prawej do lewej) czyli zmniejszamy idx o 1, aż text[idx] przestanie być spacją. I mamy indeks, w którym po prawej stronie zaczyna się tekst.
Teraz robimy slice, tylko pamiętać musimy, że po prawej stronie jest inaczej. Zapis np. [1:10] oznacza „od indeksu 1 włącznie do indeksu 10 wyłącznie”.
My chcemy wszystko od początku do ostatniego indeksu, gdzie jeszcze tej spacji nie ma, ale włącznie z nim, stąd to +1.
Może i odrobinę się trzeba pomęczyć, aby to zrozumieć, ale tak to działa.