Analiza logów serwera

Zadanie 13 z 13 · rozdział 23Trudność: 2 z 3regexstringgrupysłowniki

Treść zadania

Serwer WWW zapisuje każde żądanie w jednym wierszu dziennika (logu), np.:

192.168.0.1 - - [10/Oct/2024:13:55:36 +0200] "GET /index.html HTTP/1.1" 200 2326

Wiersz jest poprawny, jeśli w całości ma postać IP - - [DATA] "METODA ŚCIEŻKA HTTP/W" KOD ROZMIAR, gdzie poszczególne elementy oddziela dokładnie jedna spacja, a:

  • IP — cztery liczby (każda z 1–3 cyfr) oddzielone kropkami,
  • - - — dosłownie dwa myślniki oddzielone spacją,
  • [DATA] — nawias kwadratowy, co najmniej jeden dowolny znak różny od ], nawias zamykający,
  • METODA — co najmniej jedna wielka litera A–Z (np. GET, POST),
  • ŚCIEŻKA — zaczyna się od / i nie zawiera spacji,
  • W — wersja protokołu: cyfra, kropka, cyfra (np. 1.1),
  • KOD — kod odpowiedzi: dokładnie 3 cyfry,
  • ROZMIAR — liczba bajtów (same cyfry) albo -.

Wczytaj wiersze logu. Dla poprawnych wierszy policz, ile razy wystąpił każdy kod odpowiedzi, i znajdź najczęściej odwiedzaną ścieżkę. Policz też wiersze niepoprawne.

Dane wejściowe

  • 1. linia: n — liczba wierszy logu
  • kolejne n linii: wiersze logu

Dane wyjściowe

  • Dla każdego kodu, który wystąpił: linia KOD: liczba, kody rosnąco.
  • Linia Najczęstsza ścieżka: ŚCIEŻKA (liczba). Jeśli kilka ścieżek ma tę samą największą liczbę wystąpień, wybierz najmniejszą z nich w porządku sorted().
  • Ostatnia linia: Błędne wiersze: liczba.

Jeśli nie ma żadnego poprawnego wiersza, zamiast pierwszych dwóch części wypisz Brak poprawnych wpisów. (a potem linię z liczbą błędnych wierszy).

Ograniczenia

  • $1 \le n \le 1000$

Uwagi

  • Grupy nazwane (?P<nazwa>...) pozwalają odczytać fragment dopasowania po nazwie zamiast po numerze:
m = re.fullmatch(r"(?P<imie>\w+) ma (?P<lat>[0-9]+) lat", "Ola ma 12 lat")
print(m.group("imie"), m.group("lat"))   # Ola 12
  • re.fullmatch() zwraca None, gdy wiersz nie pasuje w całości — to właśnie wiersz błędny.
  • W klasie znaków [^\]] oznacza „dowolny znak oprócz ]”, a \S — „dowolny znak oprócz białych znaków”.

Przykład

Wejście
5
192.168.0.1 - - [10/Oct/2024:13:55:36 +0200] "GET /index.html HTTP/1.1" 200 2326
10.0.0.7 - - [10/Oct/2024:13:56:01 +0200] "GET /logo.png HTTP/1.1" 404 -
192.168.0.1 - - [10/Oct/2024:13:57:12 +0200] "POST /login HTTP/1.1" 302 512
to nie jest wpis logu
10.0.0.7 - - [10/Oct/2024:13:58:40 +0200] "GET /index.html HTTP/1.1" 200 2326
Wyjście
200: 2
302: 1
404: 1
Najczęstsza ścieżka: /index.html (2)
Błędne wiersze: 1

Potrzebujesz teorii?

Zasady obowiązujące w rozdziale 23

Poniższe zadania polegają na wczytywaniu danych ze standardowego wejścia (stdin) i wypisywaniu wyniku na standardowe wyjście (stdout). Rozwiązuj je za pomocą wyrażeń regularnych (moduł re).
Każde zadanie jest osobnym, niezależnym programem.

Konwencje wspólne:

  • Każda wartość wejściowa znajduje się w osobnej linii — wczytuj je dokładnie w podanej kolejności.
  • Tekst wielowierszowy jest poprzedzony linią z liczbą jego wierszy n — wczytaj go, wywołując input() n razy.
  • Dla wartości logicznych wypisuj dokładnie Prawda lub Fałsz.
  • Wielkość liter ma znaczenie, chyba że zadanie mówi inaczej.
  • Słowo to najdłuższy ciąg znaków dopasowywanych przez \w, czyli liter (także polskich), cyfr i znaku podkreślenia _. Każdy inny znak — spacja, interpunkcja, myślnik — rozdziela słowa, np. biało-czerwona to dwa słowa: biało i czerwona. Granicę słowa w wyrażeniu regularnym oznacza \b.
  • Program nie wypisuje komunikatów typu „Podaj tekst:”. Tekst podany w input("…") jest ignorowany przez sprawdzarkę.

Zadanie pochodzi z otwartego zbioru Nauka-Programowania (z rozwiązaniami wzorcowymi). Zgłoś błąd w treści lub testach.

Python uruchomi się w przeglądarce przy pierwszym teście.

Kod zapisuje się automatycznie w tej przeglądarce. Tab wstawia wcięcie; aby opuścić edytor klawiaturą, naciśnij Esc, a potem Tab.

Testy

Program dostaje „Wejście” przez input() i musi wypisać „Oczekiwane wyjście”. Liczby porównywane są z tolerancją 0,01, a tekst podany w input("…") nie jest sprawdzany.

Test 1

Nie uruchomiono
Wejście
4
1.1.1.1 - - [11/Oct/2024:08:00:00 +0200] "GET /about HTTP/1.1" 200 10
1.1.1.1 - - [11/Oct/2024:08:00:00 +0200] "GET /index.html HTTP/1.1" 200 10
2.2.2.2 - - [11/Oct/2024:08:00:00 +0200] "GET /index.html HTTP/1.0" 304 -
2.2.2.2 - - [11/Oct/2024:08:00:00 +0200] "POST /about HTTP/1.1" 201 5
Oczekiwane wyjście
200: 2
201: 1
304: 1
Najczęstsza ścieżka: /about (2)
Błędne wiersze: 0

Test 2

Nie uruchomiono
Wejście
9
10.0.0.1 - - [x] "GET / HTTP/1.1" 20 100
10.0.0.1 - - [x] GET / HTTP/1.1 200 100
10.0.0.1 - - [x] "GET / HTTP/1.1" 200 abc
10.0.0.1 - - [x] "get / HTTP/1.1" 200 100
10.0.0.1 - - [x] "GET index.html HTTP/1.1" 200 100
10.0.0.1 - - [x] "GET / HTTP/1.1" 200 100 extra
1000.0.0.1 - - [x] "GET / HTTP/1.1" 200 100
10.0.0.1 - -  [x] "GET / HTTP/1.1" 200 100
10.0.0.1 - - [x] "DELETE /api/item/7 HTTP/2.0" 500 0
Oczekiwane wyjście
500: 1
Najczęstsza ścieżka: /api/item/7 (1)
Błędne wiersze: 8

Test 3

Nie uruchomiono
Wejście
5
5.6.7.8 - - [11/Oct/2024:08:00:00 +0200] "GET /szukaj?q=kot HTTP/1.1" 200 1500
5.6.7.8 - - [11/Oct/2024:08:00:00 +0200] "GET /szukaj?q=pies HTTP/1.1" 200 1400
9.9.9.9 - - [11/Oct/2024:08:00:00 +0200] "GET /szukaj?q=kot HTTP/1.1" 200 1500
9.9.9.9 - - [11/Oct/2024:08:00:00 +0200] "GET /favicon.ico HTTP/1.1" 404 -
9.9.9.9 - - [11/Oct/2024:08:00:00 +0200] "GET /szukaj?q=kot HTTP/1.1" 500 -
Oczekiwane wyjście
200: 3
404: 1
500: 1
Najczęstsza ścieżka: /szukaj?q=kot (3)
Błędne wiersze: 0

Test 4

Nie uruchomiono
Wejście
3
8.8.8.8 - - [10/Oct]/2024] "GET /a HTTP/1.1" 200 1
8.8.8.8 - - [10/Oct/2024] "GET /b HTTP/1.1" 200 1
8.8.8.8 - - [10/Oct/2024] "GET /a HTTP/1.1" 404 1
Oczekiwane wyjście
200: 1
404: 1
Najczęstsza ścieżka: /a (1)
Błędne wiersze: 1

Test 5

Nie uruchomiono
Wejście
1
127.0.0.1 - - [01/Jan/2025:00:00:00 +0000] "GET / HTTP/1.1" 301 0
Oczekiwane wyjście
301: 1
Najczęstsza ścieżka: / (1)
Błędne wiersze: 0

Test 6

Nie uruchomiono
Wejście
2
hello
"GET / HTTP/1.1" 200 1
Oczekiwane wyjście
Brak poprawnych wpisów.
Błędne wiersze: 2
Uruchom z własnymi danymi