Строки — это рабочая лошадка Python. Любые данные из файлов, сети, терминала и логов приходят к вам текстом. Поэтому умение уверенно резать, чистить и собирать строки — это не «отдельная тема», а повседневный навык.

Один пример на всю статью: разбираем простой лог и делаем из него понятные человеку сообщения.

Chatgpt image 5 дек. 2025 г., 17 25 54

Сначала сделаем полезное дело

Есть лог. Каждая строка — одно событие.

2025-12-05 10:15:12 | INFO  | user=alice | action=login  | ip=1.2.3.4
2025-12-05 10:17:03 | ERROR | user=bob   | action=pay    | ip=5.6.7.8 | msg=card_declined
2025-12-05 10:18:44 | INFO  | user=alice | action=logout | ip=1.2.3.4

Нужно вытащить только ошибки и вывести так:

10:17:03 bob pay card_declined

Пишем короткий прототип.

log_text = """2025-12-05 10:15:12 | INFO  | user=alice | action=login  | ip=1.2.3.4
2025-12-05 10:17:03 | ERROR | user=bob   | action=pay    | ip=5.6.7.8 | msg=card_declined
2025-12-05 10:18:44 | INFO  | user=alice | action=logout | ip=1.2.3.4
"""

for line in log_text.splitlines():
    if "ERROR" in line:
        parts = line.split("|")

        time_str = parts[0].strip().split()[1]
        user = parts[2].strip().split("=")[1]
        action = parts[3].strip().split("=")[1]
        msg = parts[5].strip().split("=")[1]

        print(time_str, user, action, msg)

Прототип работает. Теперь разберёмся, почему.

Разбираем, как это устроено

Разделяем текст на строки: splitlines

for line in log_text.splitlines():

splitlines() превращает многострочный текст в список строк.
Дальше мы работаем с каждой строкой отдельно.

Режем строку на поля: split("|")

parts = line.split("|")

Лог устроен просто: поля разделены символом |.
После split получаем список кусочков. Например, для строки с ошибкой:

  • parts[0]"2025-12-05 10:17:03 "
  • parts[1]" ERROR "
  • parts[2]" user=bob "
  • parts[3]" action=pay "

Чистим пробелы: strip

Каждый кусок имеет пробелы по краям, их нужно срезать:

parts[2].strip()

strip() убирает пробелы слева и справа. Это стандартный «пылесос» для текста.

Достаём дату и время: split() без аргументов

time_str = parts[0].strip().split()[1]

parts[0] содержит дату и время через пробел.
split() без аргументов режет по любым пробелам, поэтому:

  • [0] → дата
  • [1] → время

Берём время.

Достаём значения из ключ=значение

user = parts[2].strip().split("=")[1]

Лог пишет поля как user=bob.
Режем по = и берём правую часть.

Дальше улучшаем и расширяем

📢 Подписывайтесь на наш Telegram-канал.

Там вы найдете анонсы обучающих статей и видео, готовый код для ваших проектов и увлекательные курсы. Ничего лишнего — только практика, вдохновение и развитие.

👉 https://t.me/codelab_channel

Прототип хорош для демонстрации, но он хрупкий:

  • индексы parts[5] легко перепутать;
  • если поле msg не пришло — код упадёт;
  • читаеть сложно.

Сделаем парсер аккуратным, но всё ещё простым.

Шаг 1. Превращаем строку лога в словарь

def parse_line(line):
    parts = [p.strip() for p in line.split("|")]

    date_str, time_str = parts[0].split()
    level = parts[1]

    data = {"date": date_str, "time": time_str, "level": level}

    for p in parts[2:]:
        if "=" in p:
            key, value = p.split("=", 1)
            data[key] = value.strip()

    return data

Что важно:

  • [p.strip() for p in ...] — одним движением чистим все поля.
  • split("=", 1) — режем только по первому =. Это безопаснее.
  • складываем всё в словарь data: теперь доступ по имени, а не по номеру.

Использование split("=", 1) гарантирует, что если в значении есть знак равенства, он не разобьёт строку на лишние части.

Шаг 2. Используем этот парсер

for line in log_text.splitlines():
    record = parse_line(line)

    if record["level"] == "ERROR":
        time_str = record["time"]
        user = record.get("user", "unknown")
        action = record.get("action", "unknown")
        msg = record.get("msg", "-")

        print(f"{time_str} {user} {action} {msg}")

Тут появляются два важных приёма:

  • get("msg", "-") — если поля нет, берём дефолт. Парсер не падает.
  • f-строки — собираем читабельный вывод.

Шаг 3. Делаем сводку: join

Хотим узнать, кто вообще попадал в ошибки.

error_users = set()

for line in log_text.splitlines():
    record = parse_line(line)
    if record["level"] == "ERROR":
        error_users.add(record.get("user", "unknown"))

users_line = ", ".join(sorted(error_users))
print(f"Ошибки у пользователей: {users_line}")

join — лучший способ собрать строку из набора строк.
Он и быстрее, и чище, чем склеивание через + в цикле.

Шаг 4. Срезы для косметики вывода

Если во время хочется только часы и минуты:

short_time = record["time"][:5]   # "10:17"

Срезы — быстрый способ брать нужную часть строки без дополнительных методов.

Что вы забрали из примера

На одном логе вы поработали почти со всем «строковым набором»:

  • splitlines() — разбить текст на строки.
  • split("|"), split("=") — разложить строку на поля.
  • strip() — убрать шум по краям.
  • get() — безопасно взять поле.
  • f-строки — собрать вывод.
  • join() — собрать сводку.
  • срезы [:5] — вынуть кусок строки.

И это ровно те операции, которые вы будете делать с любым текстом: логи, CSV, конфиги, ответы API.

Практика на том же примере

Продолжите развивать этот парсер:

  • Фильтр по пользователю: вводите имя — выводятся только его ошибки.
  • Подсчёт ошибок по action: вывести, какие действия ломаются чаще всего.
  • Вывод времени без секунд: используйте time[:5].

Один лог, один парсер, только расширение.