- Home »

Как проверить, содержит ли строка другую строку в Python
Если вы администрируете серверы, парсите логи или пишете скрипты автоматизации, то рано или поздно столкнётесь с задачей поиска подстроки в строке. Это одна из самых частых операций в Python, особенно при работе с конфигурационными файлами, анализе системных логов или обработке данных. В этой статье разберём все способы проверки вхождения строки в строку — от базовых до продвинутых методов с регулярными выражениями.
🔍 Базовые методы проверки вхождения строки
Самый простой и интуитивный способ — использовать оператор in
. Он возвращает True
или False
в зависимости от того, найдена ли подстрока:
text = "nginx: [error] 404 - page not found"
if "error" in text:
print("Найдена ошибка в логе")
# Выводим: Найдена ошибка в логе
Оператор in
чувствителен к регистру, поэтому "ERROR"
и "error"
— это разные строки. Для игнорирования регистра используйте lower()
:
log_line = "NGINX: [ERROR] Connection refused"
if "error" in log_line.lower():
print("Найдена ошибка (регистр игнорируется)")
🛠️ Методы строк для поиска подстроки
Python предоставляет несколько встроенных методов для более гибкого поиска:
find() и rfind()
Возвращают позицию первого (или последнего) вхождения подстроки. Если подстрока не найдена, возвращается -1:
access_log = "192.168.1.100 - - [25/Dec/2023:10:00:00 +0000] GET /index.html 200"
ip_position = access_log.find("192.168")
if ip_position != -1:
print(f"IP адрес найден на позиции: {ip_position}")
# Выводим: IP адрес найден на позиции: 0
startswith() и endswith()
Проверяют, начинается ли или заканчивается ли строка определённой подстrokой:
server_name = "web-server-01.example.com"
if server_name.startswith("web-"):
print("Это веб-сервер")
if server_name.endswith(".com"):
print("Домен верхнего уровня: .com")
count()
Подсчитывает количество неперекрывающихся вхождений подстроки:
nginx_conf = """
server {
server_name example.com;
server_name www.example.com;
}
"""
server_count = nginx_conf.count("server_name")
print(f"Директива server_name встречается {server_count} раз")
🎯 Регулярные выражения для сложного поиска
Для более сложных паттернов поиска используйте модуль re
:
import re
log_entry = "2023-12-25 10:30:45 [ERROR] Database connection failed"
# Поиск IP-адресов
ip_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
if re.search(ip_pattern, log_entry):
print("Найден IP-адрес")
# Поиск временных меток
time_pattern = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'
if re.search(time_pattern, log_entry):
print("Найдена временная метка")
⚡ Практические примеры для системного администрирования
Анализ логов Apache/Nginx
def analyze_access_log(log_line):
errors = []
# Проверка на ошибки 4xx и 5xx
if " 4" in log_line or " 5" in log_line:
if " 404 " in log_line:
errors.append("404 Not Found")
elif " 500 " in log_line:
errors.append("500 Internal Server Error")
# Проверка на подозрительные запросы
suspicious_patterns = ["/admin", "/wp-admin", ".php", "sql"]
for pattern in suspicious_patterns:
if pattern in log_line.lower():
errors.append(f"Подозрительный запрос: {pattern}")
return errors
# Пример использования
log_lines = [
'192.168.1.100 - - [25/Dec/2023:10:00:00 +0000] "GET /admin/login.php HTTP/1.1" 404 142',
'10.0.0.1 - - [25/Dec/2023:10:00:01 +0000] "GET /index.html HTTP/1.1" 200 1234'
]
for line in log_lines:
issues = analyze_access_log(line)
if issues:
print(f"Проблемы в строке: {issues}")
Проверка конфигурационных файлов
def check_nginx_config(config_content):
checks = {
"SSL включён": "ssl_certificate" in config_content,
"Gzip сжатие": "gzip on" in config_content,
"Кеширование": "expires" in config_content or "cache" in config_content,
"Безопасные заголовки": "add_header" in config_content
}
return checks
# Чтение конфигурации
with open('/etc/nginx/nginx.conf', 'r') as f:
config = f.read()
results = check_nginx_config(config)
for check, passed in results.items():
status = "✅" if passed else "❌"
print(f"{status} {check}")
📊 Сравнение производительности методов
Метод | Скорость | Гибкость | Случаи использования |
---|---|---|---|
in |
Очень быстро | Низкая | Простая проверка вхождения |
find() |
Быстро | Средняя | Нужна позиция подстроки |
startswith()/endswith() |
Быстро | Средняя | Проверка префиксов/суффиксов |
re.search() |
Медленно | Очень высокая | Сложные паттерны поиска |
🚀 Автоматизация с помощью поиска подстрок
Мониторинг системных процессов
import subprocess
def check_service_status(service_name):
try:
result = subprocess.run(['systemctl', 'status', service_name],
capture_output=True, text=True)
if "active (running)" in result.stdout:
return "running"
elif "inactive" in result.stdout or "dead" in result.stdout:
return "stopped"
else:
return "unknown"
except Exception as e:
return f"error: {e}"
# Проверка критических сервисов
critical_services = ['nginx', 'mysql', 'redis']
for service in critical_services:
status = check_service_status(service)
print(f"{service}: {status}")
Парсинг системной информации
def parse_memory_info():
with open('/proc/meminfo', 'r') as f:
meminfo = f.read()
memory_stats = {}
for line in meminfo.split('\n'):
if 'MemTotal:' in line:
memory_stats['total'] = int(line.split()[1])
elif 'MemAvailable:' in line:
memory_stats['available'] = int(line.split()[1])
elif 'SwapTotal:' in line:
memory_stats['swap_total'] = int(line.split()[1])
return memory_stats
# Использование
mem_info = parse_memory_info()
print(f"Общая память: {mem_info['total']} KB")
print(f"Доступная память: {mem_info['available']} KB")
💡 Продвинутые техники и трюки
Множественный поиск с any() и all()
error_keywords = ['error', 'failed', 'exception', 'timeout']
warning_keywords = ['warning', 'deprecated', 'slow']
log_line = "Database connection failed with timeout error"
# Проверка на наличие любого из ключевых слов ошибки
has_error = any(keyword in log_line.lower() for keyword in error_keywords)
print(f"Содержит ошибку: {has_error}")
# Проверка на наличие всех ключевых слов
has_all_keywords = all(keyword in log_line.lower() for keyword in ['database', 'connection'])
print(f"Содержит все ключевые слова: {has_all_keywords}")
Кеширование результатов поиска
from functools import lru_cache
@lru_cache(maxsize=1000)
def cached_string_search(text, pattern):
"""Кеширование результатов поиска для часто используемых паттернов"""
return pattern in text
# Особенно полезно при обработке больших логов
large_log = "..." * 10000 # Большой лог-файл
print(cached_string_search(large_log, "error")) # Первый вызов
print(cached_string_search(large_log, "error")) # Второй вызов - из кеша
🔗 Интеграция с другими инструментами
Если вы планируете разворачивать Python-скрипты для мониторинга на продакшн-серверах, рекомендую использовать VPS с предустановленным Python или выделенный сервер для более ресурсоёмких задач обработки логов.
Интеграция с systemd для мониторинга
#!/usr/bin/env python3
import subprocess
import time
def monitor_journal_for_errors():
"""Мониторинг systemd journal на предмет ошибок"""
cmd = ['journalctl', '-f', '-u', 'nginx', '--no-pager']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, text=True)
for line in iter(process.stdout.readline, ''):
if any(error in line.lower() for error in ['error', 'failed', 'critical']):
print(f"🚨 Найдена ошибка: {line.strip()}")
# Здесь можно добавить отправку уведомления
if __name__ == "__main__":
monitor_journal_for_errors()
🧪 Тестирование и отладка
Всегда тестируйте ваши скрипты поиска на различных входных данных:
def test_log_analyzer():
test_cases = [
("Normal request", "GET /index.html 200", False),
("404 error", "GET /missing.html 404", True),
("SQL injection attempt", "GET /search?q='; DROP TABLE users; --", True),
("Empty string", "", False),
("Unicode characters", "GET /файл.html 200", False)
]
for description, log_line, expected_alert in test_cases:
result = analyze_access_log(log_line)
has_alert = len(result) > 0
status = "✅" if has_alert == expected_alert else "❌"
print(f"{status} {description}: {result}")
test_log_analyzer()
🎯 Заключение и рекомендации
Выбор метода поиска подстроки зависит от ваших конкретных задач:
- Используйте
in
для простых проверок вхождения — это самый быстрый способ - Применяйте
find()
когда нужно знать позицию подстроки - Выбирайте
startswith()/endswith()
для проверки префиксов и суффиксов - Используйте регулярные выражения только для сложных паттернов — они медленнее
- Кешируйте результаты при обработке больших объёмов данных
Помните о регистрозависимости и всегда тестируйте скрипты на реальных данных. При работе с логами используйте генераторы для экономии памяти, а для критических систем добавляйте обработку исключений.
Дополнительные ресурсы:
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.