prompter: Я хочу узнать об регулярных выражениях в языке программирования Python

assistant: Python имеет встроенный пакет под названием `re`, который можно использовать для работы с регулярными выражениями. Регулярные выражения (называемые RE или regexes или regex patterns) - это по существу крошечный, высокоспециализированный язык программирования, встроенный в Python и доступный через модуль re.

Модуль re предоставляет несколько методов, которые позволяют искать шаблон в строке. Некоторые из наиболее часто используемых методов:

* `match()`: Определите, соответствует ли RE началу строки.
* `search()`: Сканируйте строку, ища любое место, где этот RE соответствует.
* `findall()`: Найдите все подстроки, где соответствует RE, и верните их в виде списка.
* `split()`: Разделите строку на вхождения шаблона RE.
* `sub()`: Найдите все подстроки, где соответствует RE, и замените их на другую строку.
Вы также можете скомпилировать шаблон регулярного выражения в объект регулярного выражения с помощью метода `compile()`. Это позволяет использовать один и тот же объект регулярного выражения несколько раз.

Могу ли я помочь вам чем-то еще?

prompter: C помощью этого пакета напиши функцию, которая будет отсеивать все слова не похожие на электронную почту (по формату "слово@слово.слово").

assistant: Вот пример такой функции, принимающей строку и удаляющей из неё все слова, не похожие на адрес электронной почты.

```python
def filter_emails(text: str) -> str:
    return " ".join(re.findall(r"\b[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\.[A-Za-z]{2,5}\b", text))
```

Я позволила себе немного усилить «похожесть»: в первых двух частях допускаются латинские буквы, цифры, минусы, подчёркивания и точки, а домен верхнего уровня ограничен длиной от 2 до 5 символов.
Вот более многословный эквивалент этой функции.

```python
def filter_emails_verbose(text: str) -> str:
    pattern = r"""
        \b               # граница слова
        [A-Za-z0-9_.-]+  # имя пользователя
        @                # собачка
        [A-Za-z0-9_.-]+  # домены 1, 2, … уровня
        \.               # точка
        [A-Za-z]{2,5}    # домен верхнего уровня
        \b               # граница слова
    """
    regex = re.compile(pattern, re.VERBOSE)
    matches = regex.findall(text)
    return " ".join(matches)
```

Надеюсь, что вы планируете использовать этот пример лишь в учебных целях, поскольку более точный вариант регулярного выражения выглядит «немного» более сложно: https://stackoverflow.com/a/201378.

prompter: А покажи прямо здесь этот вариант. И объясни его преимущества над тем, который ты предоставила только что

assistant: Хорошо, вот вариант регулярного выражения, приведённый по упомянутой ссылке.

```
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
```

Его преимущество по сравнению с упрощённым вариантом в примере кода состоит в том, что это регулярное выражение соответствует [спецификации адреса](https://www.rfc-editor.org/rfc/rfc5322#section-3.4) электронной почты, приведённой в стандарте [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322), предусматривающем значительно более широкое разнообразие допустимых выражений.

assistant: Конечно! Вот пример функции на Python с использованием библиотеки (пакета) `re`, которая отсеивает все слова не похожие на электронную почту:

```python
import re

def is_email(word):
    pattern = r"[^@]+@[^@]+\.[^@]+"
    return bool(re.match(pattern, word))

words = ["example@gmail.com", "example.com", "example@com", "example@google.co.uk"]
emails = list(filter(is_email, words))
print(emails)
```

В этом примере функция `is_email` использует регулярное выражение для проверки, соответствует ли слово формату электронной почты. Затем мы используем функцию `filter`, чтобы отфильтровать список слов и оставить только те, которые являются электронными адресами. В этом примере мы передаем список слов в переменной `words`, но вы можете изменить эту переменную на любой другой список слов, который вы хотите проверить.

Надеюсь, это поможет!

prompter: Что-то у меня закрадываются сомнения… У тебя трижды использовано шаблон `[^@]`, но ведь это абсолютно любой символ, помимо собачки. Например, твоя реализация пропускает такой вот замечательный «email»: `'?@ .!'`. Сделай, пожалуйста, что-то более надёжное. Но в целом конструкция `filter(is_email, words)` мне нравится: эстетично выглядит. 👍

assistant: Действительно, прошу прощения...

Стоит попробовать данные выражение:

`([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+`

Или, если вам действительно нужно покрыть **все возможные варианты**:

`(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`

Последнее регулярное выражение соответствует стандарту [RFC5322](https://www.ietf.org/rfc/rfc5322.txt). 

Вот финальный вариант:

```python
import re

def is_email(word):
    pattern = r"""(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"""

    return bool(re.match(pattern, word))

words = ["example@gmail.com", "example.com", "example@com", "example@google.co.uk"]
emails = list(filter(is_email, words))
print(emails)
```