In [1]:
# setup
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

3. Zaawansowana praca z tekstem

Łańcuchy tekstowe różnią się od porstych typów numerycznych i obok list i krotek zaliczają się do sekwencyjnych typów danych. Oznacza to że podobnie jak listy i łańcuchy są uporządkowaną kolekcją elementów, gdzie położenie każdego elementu jest ściśle określone. Z tego powodu łańcuchy tekstowe mogą być przetwarzane w sposób podobny do przetwarzania list.

Dostęp do poszczególnych znaków w łańcuchu tekstowym

łańcuchy tekstowe indeksuje się w taki sam sposób jak listy i krotki. Indeks wskazuje, który znak łańcuch tekstowego ma zostać wybrany.

python[1] wskzuje, że chcemy wybrać znak ze zmiennej python znajdujący się na pozycji 1. Pamiętajmy, w języku Python numerowanie pozycji zaczyna się od 0, nie od 1. P jest „zerowym” znakiem, y jest pierwszym znakiem, t jest drugim znakiem.

P y t h o n
[0] [1] [2] [3] [4] [5]
In [2]:
python = 'python'
python[0]
python[1]
python[-1]
Out[2]:
'p'
Out[2]:
'y'
Out[2]:
'n'

Wycinanie fragmentów i modyfikacje łańcuchów

Dzięki dostępowi do poszczególnych elementów łańcucha możemy je modyfikować wykorzystując indeksy. W przypadku wycinania łańcuchów tekstowych stosujemy takie zasady jak przy wicinaniu fragmentów list. W nawiasie kwadratowym możemy podać pojedyńczą liczbę np.[1] aby uzyskać znak na pozycji pierwszej lub też zakres liczby aby uzyskać kilka znaków.

Łańuchy tekstowe, podobnie jak krotki są niezmienne (ang. Immutable). Oznacza to, że nie można dokonywać zmian w istniejącym łańuchu tektowym. Jeśli chcemy zmodyfikować łańcuch, musimy utworzyć nowy łańuch zawierający zmianę, a właściwie skleić nowy łańcuch z fragmentów łancucha modyfikowanego i nowego łańcucha.

Jako przykład zmodyfikujemy w zmiennej python małą literę na dużą a wyniki zapiszemy w nowej zmiennej Python

In [3]:
Python = 'P'+ python[1:]
Python
Out[3]:
'Python'

Zamiana listy na łańcuch tekstowy i odwrotnie

Z punktu widzenia organizacji danych w pamięci łańcuch tekstowy i lista/krotka znaków to jedno i to samo. Pyhton dostarcza wiele narzędzi do przetwarzania i zarządzania łańcuchami tekstowymi, formatowaniem tekstu itp. Szczegóły można znaleść na: [https://docs.python.org/3/library/string.html]

W tum miejscu, jako przykład zostaną pokazane dwie metody obiektu string, które pozwalają zamienić łańcuch tekstowy na listę oraz operację odwrotną.

Aby jednak napis na litery należy po prostu zastosować funkcję list(). Dowolny łańcuch tekstowy możemy zamienić też na listę stosując metodę str.split(), gdzie argumentem metody split() będzie znak rozdzielający. Domyślnie jest to tzw. biały znak (whitespace) czyli spacja " ", tabulator "\t" i koniec wiersza definiowany funkcją os.linespace() z biblioteki zewnętrzenej os. Można wskazać jednak dowolny znak (tu "z").

In [4]:
napis = "Brzeczeszczykiewicz"
napis.split("z")
list(napis)
Out[4]:
['Br', 'ec', 'es', 'c', 'ykiewic', '']
Out[4]:
['B',
 'r',
 'z',
 'e',
 'c',
 'z',
 'e',
 's',
 'z',
 'c',
 'z',
 'y',
 'k',
 'i',
 'e',
 'w',
 'i',
 'c',
 'z']

Aby połączyć listę w napis, należy przekazać listę jako operator do metody str.join(), gdzie string (może być pusty) zamieni się w łącznik pomiędzy elementami listy. Niestety wszystkie elementy listy muszą być typu string. Jeżeli mamy wątpliwości czy wszystkie elementy listy to łańcuchy tekstu należy wcześniej zamienić na string.

In [5]:
lista = ['a','b','f','k',"l"]
"".join(lista)
Out[5]:
'abfkl'

Najważniejsze funkcje modyfikacji łańcuchów tekstu

Obiekt łańcuch tekstowy (string) posiada kilkadziesiąt metod, które pozwalają zmodyfikować wygląd napisu. Ogólna składnia tych metod to:

zmienna_napis.methoda([args])

Nazwy wszystkich metod formatujących można znaleść wpisując dir(str):

>>> dir(str)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

Opis metod znajduje się z dokumentacji języka: [https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str]

Kilka prostych przykładów związanych z zamianą wielkosci liter, bardzo przydatnych do unifikacji wzorców przechowywanych w programie i danych wprowadzanych przez użytkownika:

In [6]:
napis = 'tekst do Modyfikacji'
print(napis.upper())
print(napis.lower())
print(napis.title())
TEKST DO MODYFIKACJI
tekst do modyfikacji
Tekst Do Modyfikacji

Niektóre funkcje tekstowe przydają się do identyfikowania/formatowania liczb na przykład w celu budowania sortowalnych nazw plików. Funkcje zfill() wyrównuje liczby do jednej długości, dodając poprzedzające zera - nie zmieniają wartości ale umożliwiają prawidłowe sortowanie napisów zawierających cyfry.

In [7]:
print("file_" + str(10).zfill(4)) 
print("file_" + str(100).zfill(4))
file_0010
file_0100

Formatowanie tekstu pozwala również dodawać/usuwać spacje w celu wyrównywania (justyfikacji) długości napisów.

In [8]:
"napis".rjust(10)
"napis".ljust(10)
"     napis".strip()
Out[8]:
'     napis'
Out[8]:
'napis     '
Out[8]:
'napis'

Zaawansowane formatowanie tekstu

Metody formatowania tekstu związane ze sklejaniem list i łańcuchów nie są najlepszym narzędziem, jeżeli zależy nam na wysokiej jakości kodu i skutecznego formatowaniu danych wyjściowych, zwłaszcza jeżeli te ostatnie zawierają wartości zmiennoprzecinkowe co wymaga dodatkowej konwersji na łańcuch tekstowy.

Note: Zewnętrzne moduły - biblioteka standardowa

Jak wspomniano we wcześniejszej części kursu lista funkcji wbudowanych w języku Python jest bardzo ograniczona. Wiele funkcji podstawowych jest zawarta w zewnętrznych bibliotekach, takich jak math (operacje matematyczne) czy os - (funcje systemu operacyjnego). Zestaw bibliotek, który dostarczany jest razem z aktualną wersją języka nosi nazwę biblioteki standardowej. Po zaimportowaniu modułu math dostępne są wszystkie jego funkcje z przedrostkiem w postaci nazwy biblioteki. Szczegółowe zastosowanie modułów zewnętrznych zostanie omówione w daleszej części kursu.

Jako przykład zaprezentujemy wyświetlenie napisu informującego o przybliżonej wartości pierwiastka z dwóch. Opracja wymaga:

  1. Importu biblioteki
  2. Wyliczenie wartości
  3. Zaokrąglenie do 3 miejsc po przecinku
  4. Zamiana na łańcuch i połączenie z literałem "Pierwiastek z dwoch to "
In [9]:
import math #1
k = math.sqrt(2) #2
print(k)

"Pierwiastek z dwoch to " + str(round(math.sqrt(2),3)) #3 i 4
1.4142135623730951
Out[9]:
'Pierwiastek z dwoch to 1.414'

Bardziej zaawansowane metody pozwalają na zastępowanie określonych fragmetów tekstu zmiennymi określonego typu. Fragmenty tekstu wymagające zastąpienia oznacza się odpowiednio %d dla liczb całkowitych %s dla łańcuchów znaków i %f dla liczb zmiennoprzecikowych. Mechanizm ten pozwala również na definiowanie wyglądu wprowadzanego łańcucha, wstawianych zer, czy ilości miejsc po przecinku, bez konieczności stosowania dodatkowych funkcji matematycznych.

Sposób formatowania określany jest przez wzorzec ####

In [10]:
'To jest liczba: %f' % math.sqrt(2) #formatowanie zwykłe
'To jest liczba: %1.3f zaokraglona' % math.sqrt(2) # zaokrąglanie
'To jest liczba: %6.1f' % math.sqrt(2) # wyrównanie do ilości znaków
'To jest liczba: %6.3f' % math.sqrt(2) # wyrównanie do ilości znaków
'To jest liczba: %06.1f' % math.sqrt(2) # wyrównanie do ilości znaków z zerami na początku
Out[10]:
'To jest liczba: 1.414214'
Out[10]:
'To jest liczba: 1.414 zaokraglona'
Out[10]:
'To jest liczba:    1.4'
Out[10]:
'To jest liczba:  1.414'
Out[10]:
'To jest liczba: 0001.4'
In [11]:
'to jest napis: %s' % 'moj tekst'
'to jest napis: %20s' % 'moj tekst bardzo bardzo dlugi' #o długosci 20 znakow'
Out[11]:
'to jest napis: moj tekst'
Out[11]:
'to jest napis: moj tekst bardzo bardzo dlugi'

Nowy sposób formatowania miejsca wstawiania zmiennych markuje {} dodatkowo oznaczając, która zmienna ma znaleść się w danym miejscu. Zmienne do sformatowania modyfikuje się funkcją format. Należy zazaczyć, że w przypadku gdy zmienna ma zostać wyświetlona jak jest trzeba iloscią wyświetlanych znaków

In [12]:
'To jest liczba: {0:%<f}'.format( math.sqrt(2))
'To jest liczba: {0:%<3f}'.format( math.sqrt(2)) # minimum 3 znaki
Out[12]:
'To jest liczba: 1.414214'
Out[12]:
'To jest liczba: 1.414214'
In [13]:
'to jest napis: {0:%<s}'.format('moj tekst') 
'to jest napis: {0:%<10s}'.format('moj tekst bardzo bardzo dlugi')  #o długosci 20 znakow'
Out[13]:
'to jest napis: moj tekst'
Out[13]:
'to jest napis: moj tekst bardzo bardzo dlugi'

Rozwiązanie szczególnie przydatne przy formatowaniu napisów i liczb o różnej długości, baz konieczności ręczego liczenia długości poszczególnych łańcuchów.

In [14]:
'{0:<40s} {1:1.3f}'.format('Pierwiastek z dwoch:',math.sqrt(2))
'{0:<40s} {1:1.3f}'.format('Pierwierwiastek z dziesieciu:',math.sqrt(10))
Out[14]:
'Pierwiastek z dwoch:                     1.414'
Out[14]:
'Pierwierwiastek z dziesieciu:            3.162'

Więcej na ten temat na [https://pyformat.info/]

Ćwiczenie

Przeliczyć współrzędne w stopniach dziesiętnych na stopnie minuty sekundy. Podać wynik w odpowiednim formacie. Rozwiązanie przedstawić w postaci funkcji