"""Напишите код который выполняет извлечение ссылок из сырого текста и сортирует их по определённым правилам.

Сначала извлеките уникальные 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. Регулярное выражение сохранено из условия; полноценный разбор произвольного текста с пунктуацией потребовал бы дополнительных правил.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее