W tej części zrobimy mniej więcej to, co w poprzedniej, ale na większą skalę. Nasz program robi się na tyle duży, że jeśli zajrzysz do niego za tydzień, miesiąc, nie będziesz za bardzo pamiętać, co w którym miejscu się dzieje. Dlatego w tym rozdziale dodamy komentarze do kodu programu i dodawanie komentarzy powinno ci wejść w nawyk. Lecimy!
Zacznij od pobrania 12 powieści z poniższego linku.
Jak Już wspominałem, wszystkie powieści zostały pobrane z serwisu wolnelektury.pl. Wypakuj pliki do dowolnego katalogu, w którym nie będzie żadnych innych plików, tylko te 12 plików w formacie .txt. Moglibyśmy otwierać każdy plik z osobna, każdy plik z osobna przygotować do zliczania 3-gramów i każdy taki słownik 3-gramów zapisać. Nie zrobimy tego, nie po to uczysz się programowania, żeby robić powtarzalne rzeczy! Cały urok polega na tym, by zapisać nasze potrzeby raz, a powtórzeniami powinien się zająć program. Zacznijmy od odczytania listy plików w folderze. Do operacji związanych ze ścieżkami do plików, folderów będziesz potrzebować biblioteki os. Z biblioteki zaimportujemy tylko potrzebną funkcję listdir() i sprawdzimy jej działanie:
from os import listdir
pliki = listdir("F:\\python\\ids\\")
print(pliki)
W 1 linicje importujemy potrzebną funkcję. W 2 linijce argumentem funkcji listdir() jest katalog, w którym zapisałeś wypakowane pliki, funkcję z argumentem zapisujemy pod zmienną pliki. W 4 linijce drukujemy zmienną pliki. Zobaczmy efekt:
======================== RESTART: F:/python38/wpis 11.py =======================
['Bankructwo malego Dzeka - Janusz Korczak.txt', 'Bracia Dalcz i S-ka - Tadeusz Dolega-Mostowicz.txt', 'Dr. Murek zredukowany - Tadeusz Dolega-Mostowicz.txt', 'Drugie zycie doktora Murka - Tadeusz Dolega-Mostowicz.txt', 'Dzieci ulicy - Janusz Korczak.txt', 'Dziecko salonu - Janusz Korczak.txt', 'Kajtus Czarodziej - Janusz Korczak.txt', 'Kariera Nikodema Dyzmy - Tadeusz Dolega-Mostowicz.txt', 'Kiedy znow bede maly - Janusz Korczak.txt', 'Kiwony - Tadeusz Dolega-Mostowicz.txt', 'Krol Macius na wyspie bezludnej - Janusz Korczak.txt', 'Pamietnik pani Hanki - Tadeusz Dolega-Mostowicz.txt']
Świetnie, mamy listę nazw plików, teraz możemy posłużyć się tą listą, by wskazać funkcji open() pełną ścieżkę do każdego z plików. Zróbmy to krok po kroku, wydrukujmy taką pełną ścieżkę dla każdego pliku i zaprowadźmy co nieco porządku:
from os import listdir
sciezka = "F:\\python\\ids\\"
pliki = listdir(sciezka)
for plik in pliki:
print(sciezka + plik)
Teraz w 2 linijce pod zmienną sciezka zapisany jest string prowadzący do katalogu zawierającego nasze 12 plików. W 3 linijce argumentem funkcji listdir() jest zdefiniowana wcześniej ścieżka. Powstała lista nazw plików zapisana jest pod zmienną pliki. W 5 linijce zaczynamy pętlę for. Pętla for tym razem nie porusza się po zakresie listy – brak polecenia in range. Pętla for porusza się po każdym elemencie listy, czyli przy pierwszym przejściu bierze 0 element, przy drugim przejściu 1 element itd. aż do ostatniego elementu, wtedy się kończy działanie pętli. W linijce 6 dla każdego elementu listy drukowana jest ścieżka i element listy. zobaczmy efekt:
======================== RESTART: F:/python38/wpis 11.py =======================
F:\python\ids\Bankructwo malego Dzeka - Janusz Korczak.txt
F:\python\ids\Bracia Dalcz i S-ka - Tadeusz Dolega-Mostowicz.txt
F:\python\ids\Dr. Murek zredukowany - Tadeusz Dolega-Mostowicz.txt
F:\python\ids\Drugie zycie doktora Murka - Tadeusz Dolega-Mostowicz.txt
F:\python\ids\Dzieci ulicy - Janusz Korczak.txt
F:\python\ids\Dziecko salonu - Janusz Korczak.txt
F:\python\ids\Kajtus Czarodziej - Janusz Korczak.txt
F:\python\ids\Kariera Nikodema Dyzmy - Tadeusz Dolega-Mostowicz.txt
F:\python\ids\Kiedy znow bede maly - Janusz Korczak.txt
F:\python\ids\Kiwony - Tadeusz Dolega-Mostowicz.txt
F:\python\ids\Krol Macius na wyspie bezludnej - Janusz Korczak.txt
F:\python\ids\Pamietnik pani Hanki - Tadeusz Dolega-Mostowicz.txt
Nasz pomysł działa, rozbudujmy program, by drukował pierwsze 200 znaków z każdej z książek:
from os import listdir
sciezka = "F:\\python\\ids\\"
pliki = listdir(sciezka)
#wydrukuj 200 znaków z każdego pliku w katalogu
for plik in pliki:
ksiazka = open(sciezka + plik, mode="r", encoding = "utf-8")
dwiescie_znakow = ksiazka.read(200)
print(f"200 znaków z pliku {plik} to:\
\n-------------\n{dwiescie_znakow}\n-------------\n")
W 5 linijce pojawił się komentarz. Wszystkie komentarze w Pythonie zaczynają się od znaku #. Wszystko, co znajduje się w linijce zaczynające się od # jest pomijane przez Pythona. Komentarze za to nie są pomijane przez czytającego kod. Przy takim zapisie masz jasność, do czego służy pętla. Bez dokładnego analizowania jej linijka po linijce możesz pętlę zrozumieć i wykorzystać w innym projekcie, innym programie. W 7 linijce otwierasz plik do odczytu z kodowaniem utf-8. W 8 linijce pod zmienną dwiescie_znakow przypisujesz odczytany string 200 znaków z ksiazka. W 9 linijce drukujesz te 200 znaków. Tu kończy się pętla, pętla zostanie wykonana 12 razy, dla każdego pliku znajdującego się w podanym katalogu. Zobaczmy efekt:
======================== RESTART: F:/python38/wpis 11.py =======================
200 znaków z pliku Bankructwo malego Dzeka - Janusz Korczak.txt to:
-------------
Janusz Korczak
Bankructwo małego Dżeka
Ta lektura, podobnie jak tysiące innych, jest dostępna on-line na stronie wolnelektury.pl.
Utwór opracowany został w ramach projektu Wolne Lektury przez
-------------
200 znaków z pliku Bracia Dalcz i S-ka - Tadeusz Dolega-Mostowicz.txt to:
-------------
Tadeusz Dołęga-Mostowicz
Bracia Dalcz i S-ka
(...)
Działa! Nic nie stoi na przeszkodzie, by w pętli for umieścić całą naszą dotychczasową wiedzę w postaci kodu, który policzy liczbę 3-gramów dla każdej z książek i wynik zapisze w osobnym pliku dla każdej z nich. Tutaj nic już nas nie powinno zaskoczyć! Zapiszmy program:
from os import listdir
import re
from collections import Counter
sciezka = "F:\\python\\ids\\"
pliki = listdir(sciezka)
#dla każdego pliku w katalogu
for plik in pliki:
#otwórz plik
ksiazka = open(sciezka + plik, mode="r", encoding = "utf-8")
tekst = ksiazka.read()
#przygotuj tekst do zliczania powtórzeń słów
tekst = tekst.replace("\n", " ")
tekst = tekst.lower()
tekst = re.sub("[^a-z ąćęłńóśóżź]", "", tekst)
tekst = re.sub(" +", " ", tekst)
wyrazy = tekst.split()
lista_trzech_wyrazow = []
#utwórz listę trzech kolejnych wyrazów
for indeks in range(len(wyrazy) - 2):
trzy_wyrazy = " ".join(wyrazy[indeks:indeks + 3])
lista_trzech_wyrazow.append(trzy_wyrazy)
#utwórz słownik zliczający liczbę powtórzeń trzech kolejnych wyrazów
liczba_trzygramow = Counter(lista_trzech_wyrazow)
#zapisz słowniki do pliku
trzygramy_txt = open(f"{sciezka}trzygramy{plik}", mode="w", encoding = "utf-8")
trzygramy_txt.write(str(liczba_trzygramow))
trzygramy_txt.close()
Nasz program jest już zbyt długi by tłumaczyć, co się w nim dzieje linijka po linijce. Po tylu lekcjach i zadaniach domowych na pewno doskonale wiesz, co wydarzyło się powyżej. Dla wygody wpisałem komentarze, jeśli nie są dla Ciebie jasne, w swojej wersji programu zapisz je w przyjazny dla Ciebie sposób. Sprawdźmy jak wyglądają początki plików z 3-gramami:
Kiwony:
Counter({'do przekonania że': 13, 'w każdym razie': 11, 'okazało się że': 10, 'co się stało': 10,
Król Maciuś Pierwszy:
Counter({'wasza królewska mość': 27, 'dziś popr forma': 22, 'na bezludną wyspę': 18, 'waszej królewskiej mości': 18, 'na bezludnej wyspie': 16, 'nie wie maciuś': 10, 'co to za': 10, 'pyta się maciuś': 10,
Pamietnik pani Hanki:
Counter({'w każdym razie': 40, 'o tym że': 28, 'przypisek t d': 22, 't d m': 22, 'spojrzał na mnie': 22, 'wydaje mi się': 22, 'okazało się że': 22, 'w ten sposób': 20, 'na myśl że': 20,
Już w „Pamiętniku pani Hanki” mamy dziwne 3-gramy, takie jak 'przypisek t d’ i 't d m’. Co to w ogóle znaczy? Poszukajmy w powieści w formacie .txt. Znajdujemy powtarzające się często wyrażenie „(Przypisek T. D. M.)”. Usuniemy te 3-gramy, nie są one elementem stylu pisarza, a wymuszony formą zwrot. Popatrzymy dalej:
Dziecko salonu:
Counter({'co to jest': 17, 'ja nie chcę': 13, 'idę od izby': 9, 'od izby do': 9, 'izby do izby': 9, 'mi się że': 8, 'z ciastkami na': 8, 'ciastkami na guziku': 8, 'przypis edytorski vous': 8
Tu pojawia się wysoko tajemniczy „przypis edytorski vous”. Gdy zajrzyjmy do książki znajdziemy na jej końcu przypisy:
Przypisy:
1. Palmirski, Władysław (1861–1940) — warszawski lekarz bakteriolog, zajmował się między innymi szczepieniami przeciw wściekliźnie. [przypis edytorski]
2. Młoda Polska — tu w znaczeniu: krakowska bohema artystyczna, cyganeria krakowska. [przypis edytorski]
3. bronchitis (z gr.) — bronchit, zapalenie oskrzeli. [przypis edytorski]
4. pneumonia (z łac. ) — zapalenie płuc. [przypis edytorski]
5. tyfus — choroba zakaźna znana pod kilkoma postaciami: brzuszny, plamisty, powrotny. [przypis edytorski]
6. La bonne papa (z fr. le bon papa: dobry tata) — dobra tata. [przypis edytorski]
7. hajduk — służący. [przypis edytorski]
(...)
To też nie jest nam do niczego potrzebne, przypisy zaburzają nam statystyki tekstu, przecież przypisów nie tworzył autor powieści.
Kariera Nikodema Dyzmy:
Counter({'kochany panie nikodemie': 23, 'che che che': 18, 'raz po raz': 15, 'mu na myśl': 15, 'że pan prezes': 14, 'w każdym razie': 14, 'na myśl że': 14, 'się z miejsca': 13, 'na wszelki wypadek': 12, 'przyszło mu na': 12, 'mi się że': 11, 'się z nim': 11, 'do przekonania że': 11, 'zabrał się do': 10, 'zadowolony przypis edytorski'
Tutaj też pojawia się przypis edytorski (i to w dodatku zadowolony!), to samo w „Kiedy znów będę mały” i w „Bankructwie małego Dżeka”. W następnej części poznamy pętlę if, która pomoże nam się uporać z pozbyciem się niepotrzebnych przypisów, oczywiście niepotrzebnych w analizie stylu pisarza, tak w ogóle przypisy są bardzo ważne!
Zadanie domowe
Podążanie za instrukcjami, nawet jeśli je wszystkie wykonujesz samodzielnie, nie zrobi z ciebie programisty. Zadania domowe mogą wydawać się na początku trudne. Tu nie ma rozwiązania podanego na talerzu, użyj dowolnych źródeł, by znaleźć odpowiedź.
- Zmień działanie programu tak, by wypisywał nie trzy, a cztery występujące po sobie słowa – 4-gramy
- Biblioteka os ma wiele przydatnych funkcji i metod, użyj ich, by wydrukować rozmiary plików z dowolnego katalogu (nie przesadź z liczbą plików w katalogu).