.. _przyklad07:
Słownik i obsługa plików
########################
.. note::
W tym przykładzie zobaczysz, na czym polega **zapis i odczyt plików** tekstowych w różnych formatach,
poznasz kolejną złożoną strukturę danych – **słownik** oraz nauczysz się wykonywać kolejne operacje na napisach.
Zadanie
********
Napisz program :file:`slownik.py`, który pozwoli zapisywać w pliku tekstowym obce wyrazy oraz ich możliwe znaczenia.
Program powinien pobierać dane z klawiatury w formacie: ``wyraz obcy: znaczenie1, znaczenie2, ...`` itd.
Pobieranie danych kończy naciśnięcie klawisze :kbd:`ENTER`.
Podane dane powinny być zapisywane w pliku :file:`slownik.txt` i/lub :file:`slownik.csv`.
Program powinien odczytywać wcześniej zapisane dane, a użytkownik powinien mieć możliwość
dodawania nowych i zmieniania zapisanych danych.
.. raw:: html
Kod nr
.. highlight:: python
.. literalinclude:: przyklad07_txt.py
:linenos:
Słownik
-------
Słownik (zob. :term:`słownik`) to struktura nieuporządkowanych danych w formacie *klucz:wartość*.
Kluczami mogą być m.in. napisy i liczby, które wskazują na wartości dowolnego typu,
np. inne napisy, liczby, listy, krotki itd. W programie wykorzystujemy słownik,
którego kluczami są wyrazy obce, natomiast wartościami są listy możliwych znaczeń, np.:
.. code::
slownik = {'go': ['iść', 'pojechać', 'chodzić'], 'look': ['patrzeć', 'poszukać'], 'see' : ['widzieć', 'zrozumieć']}
**Operacje na słowniku**:
* ``slownik = {}`` – utworzenie pustego słownika,
* ``slownik = { 'go':['iść','pojechać'] }`` – utworzenie 1-elementowego słownika,
* ``slownik['make'] = ['robić','tworzyć']`` – dodanie nowego elementu,
* ``slownik['go']`` – odczyt elementu wskazanego przez klucz.
Pliki tekstowe
---------------
Aby zilustrować niektóre operacje na napisach i listach, elementy słownika zapisywać
będziemy do pliku w formacie *wyraz_obcy:znaczenie1,znaczeni2,...*.
Funkcja ``otworz()`` przekształca format pliku na słownik,
a funkcja ``zapisz()`` słownik na format pliku.
**Operacje na plikach tekstowych**:
* ``os.path.isfile(plik)`` – zwraca prawdę, jeżeli podany plik istnieje,
* ``open(plik, "w")`` – otwarcie pliku w podanym trybie: ``"r"`` – odczyt(domyślny),
``"w"`` – zapis, ``"a"`` – dopisywanie,
* ``with open(nazwa_pliku) as plik:`` – otwarcie pliku w instrukcji ``with ... as ...`` zapewnia
obsługę błędów, dba o zamknięcie pliku i udostępnia go w zmiennej ``plik``,
* ``for wiersz in plik:`` – plik tekstowy można rozumieć jako sekwencję wierszy, pętla ``for`` pozwala więc na odczyt
kolejnych wierszy,
* ``plik.write(tresc)`` – zapisuje do pliku podaną treść,
* ``plik.close()`` – zamyka plik, ale lepiej używać konstrukcji z ``with``.
**Operacje na napisach**:
* ``.split(':')`` – dzieli tekst na części oddzielane podanym znakiem, zwraca je w postaci listy,
* ``','.join(lista)`` – łączy elementy listy podanym znakiem (w tym wypadku przecinkiem), zwraca tekst,
* ``.lower()`` – zamienia znaki na małe litery,
* ``.strip()`` – usuwa początkowe i końcowe białe znaki (spacje, tabulatory) oraz znaki końca wiersza,
* ``.replace('co','czym')`` – zastępuje w ciągu wszystkie wystąpienia *co – czym*,
* ``.count(znak)`` – zwraca liczbę wystąpień znaku w napisie.
W pętli głównej programu dane pobrane w formacie *wyraz_obcy:znaczenie1,znaczeni2,...*
rozbijamy na wyraz obcy i jego znaczenia, które zapisujemy w liście ``t``. Wszystkie elementy
oczyszczamy, tj. zamieniamy na małe litery i usuwamy białe znaki.
Funkcja ``map(oczysc, znaczenia)`` pozwala zastosować podaną jako pierwszy argument funkcję ``oczysc()``
do wszystkich elementów listy ``znaczenia`` podanej jako argument drugi.
Instrukcja ``list()`` przekształca zwrócony przez funkcję ``map()`` obiekt z powrotem na listę.
Format csv
----------
Dane tekstowe często zapisuje się w formacie `csv `_.
Jest to rozwiązanie wygodniejsze, ponieważ zwalnia nas od konieczności ręcznego przekształcania
odczytywanych z pliku linii na struktury danych.
Na początku pliku dodajemy import modułu: ``import csv``. Następnie zmieniamy nazwę pliku oraz funkcje
``otworz()`` i ``zapisz()`` na podane niżej:
.. raw:: html
Kod nr
.. literalinclude:: przyklad07_csv.py
:linenos:
:lineno-start: 5
:lines: 5-24
Format CSV polega na zapisywaniu wartości oddzielonych separatorem, czyli domyślnie przecinkiem.
Jeżeli wartość zawiera znak separatora, jest cytowana domyślnie za pomocą cudzysłowu.
W naszym wypadku przykładowa linia pliku przyjmie postać: ``wyraz obcy,znaczenie1,znaczenie2,...``
**Operacje na plikach CSV**
- ``csv.reader(plik)`` – metoda interpretuje podany plik jako format CSV i każdą linię zwraca w postaci listy elementów,
wyodrębnionych za pomocą separatora,
- ``csv.writer(plik)`` – metoda tworzy obiekt reprezentujący treść pliku w formacie CSV,
- ``.writerow(lista)`` – metoda umożliwia zapis listy elementów w formacie CSV w obiekcie zwróconym przez metodę
``.writer()``.
Instrukcja ``slownik[linia[0]] = linia[1:]`` zapisuje dane w słowniku, kluczem jest wyraz obcy (1 element listy),
wartościami lista znaczeń odczytana za pomocą notacji indeksowej.
Ćwiczenia
*********
1) Kod wypisujący słownik zamień na funkcję ``wypisz_slownik()`` i wykorzystaj ją do wypisywania słownika.
2) Rozszerz program tak, aby umożliwiał usuwanie elementów słownika.
3) Dodaj do programu możliwość uczenia się zapisanych w słowniku słówek, np. niech program wypisuje kolejne
słowa obce i pobiera od użytkownika możliwe znaczenie i sprawdza, czy jest poprawne.
.. admonition:: Pojęcia
:term:`słownik`, :term:`notacja wycinkowa`