Сначала извлеките уникальные URL в порядке появления, затем выделите первые N, облачные, файловые и остальные ссылки. Сортировать по длине нужно только последнюю группу; общий лимит применяют в конце.
"""Напишите код который выполняет извлечение ссылок из сырого текста и сортирует их по определённым правилам.
Сначала извлеките уникальные URL в порядке появления, затем выделите первые N, облачные, файловые и остальные ссылки. Сортировать по длине нужно только последнюю группу; общий лимит применяют в конце.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
"""Напишите код который выполняет извлечение ссылок из сырого текста и сортирует их по определённым правилам. Список ссылок который будет возвращаться не должен содержать дубликаты Правила сортировки следующие:
- Приоритет 1: Сначала идут первые обнаруженные ссылки в количестве self.first_extracted_links
- Приоритет 2: Потом идут ссылки на облачные диски и документы (Яндекс Диск и т.д.)
- Приоритет 3: Потом ссылки на файлы (в конце пути имеют расширения .exe, .pdf, .rar и так далее)
- Приоритет 4: Здесь оставшиеся ссылки отсортированные от большей к меньшей по длине строки Так же надо учитывать ограничение на количество ссылок и реализовать контекстный менеджер Запустить можно например в [link]
Итого:
- На выполнение даётся 30 минут
- Написать функции apply, process, функции для контекстного менеджера
- Все тесты должны доходить до конца
- Тесты модифицировать нельзя
- Можно использовать import'ы
- После написания можно проверить запустив локально, если что то не так, то исправить на этой странице
regex для поиска ссылок: (?:https?|ftp)://(?:[a-zA-Z0-9-]+.)[a-zA-Z0-9-]+.[a-zA-Z]{2,}(?::\d+)?(?:/[^\s()])?
"""
class LinkExtractor: DEFAULT_CLOUDS = frozenset(( "drive.google.com", "mediafire.com", "yadi.sk", "disk.yandex.ru", "cloud.mail.ru", "mega.nz" ))
# Можно расширить этот метод или переписать его
def __init__(self, max_links: int = 7, first_extracted_links: int = 2, clouds = None):
# Максимальное количество ссылок возвращаемых в массиве
self.max_links = max_links
# Количество ссылок которое извлекается для первого условия
self.first_extracted_links = first_extracted_links
# Список доменов которые считаются облаками для второго условия
self.clouds = clouds or self.DEFAULT_CLOUDS
self._results = []
# Написать этот метод, добавляет часть текста который позже надо анализировать
def apply(self, text) -> "LinkExtractor":
...
return self
Ответ
Сначала извлеките уникальные URL в порядке появления, затем выделите первые N, облачные, файловые и остальные ссылки. Сортировать по длине нужно только последнюю группу; общий лимит применяют в конце.
Ниже process() возвращает результат, а выход из контекстного менеджера вызывает его автоматически. Расширения файлов заданы явно; список можно расширить. Скрытые тесты не приложены, поэтому их прохождение не утверждается.
import re
from pathlib import PurePosixPath
from urllib.parse import urlsplit
class LinkExtractor:
DEFAULT_CLOUDS = frozenset({
'drive.google.com', 'mediafire.com', 'yadi.sk',
'disk.yandex.ru', 'cloud.mail.ru', 'mega.nz',
})
FILES = {'.exe', '.pdf', '.rar', '.zip', '.7z', '.doc', '.docx',
'.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.csv'}
PATTERN = re.compile(
r'(?:https?|ftp)://(?:[a-zA-Z0-9-]+\.)*'
r'[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(?::\d+)?(?:/[^\s()]*)?'
)
def __init__(self, max_links=7, first_extracted_links=2, clouds=None):
if max_links < 0 or first_extracted_links < 0:
raise ValueError('Limits must be nonnegative')
self.max_links = max_links
self.first_extracted_links = first_extracted_links
self.clouds = {c.lower() for c in (
self.DEFAULT_CLOUDS if clouds is None else clouds
)}
self._texts = []
self._results = []
def apply(self, text):
self._texts.append(text)
return self
def process(self):
links = list(dict.fromkeys(
url for text in self._texts for url in self.PATTERN.findall(text)
))
first = links[:self.first_extracted_links]
clouds, files, rest = [], [], []
for url in links[self.first_extracted_links:]:
parsed = urlsplit(url)
if (parsed.hostname or '').lower() in self.clouds:
clouds.append(url)
elif PurePosixPath(parsed.path).suffix.lower() in self.FILES:
files.append(url)
else:
rest.append(url)
rest.sort(key=len, reverse=True)
self._results = (first + clouds + files + rest)[:self.max_links]
return self._results.copy()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
self.process()
return False
Облачность проверяется по hostname, а не вхождением строки в URL. Регулярное выражение сохранено из условия; полноценный разбор произвольного текста с пунктуацией потребовал бы дополнительных правил.