Задача собеседования: получаем email из строки

2023-Feb-01

Сегодня мы рассмотрим очередную задачу, которую дали на собеседовании, решим задачу разными способами. Что мы изучим в этом уроке:

  • работа со строками в JS,
  • работа с регулярными выражениями в JS,
  • научимся вырезать текст между нужными символами c помощью регулярных выражений.

Несколько слов о компании. Небольшая компания. Штат программистов приблизительно 50-80 человек. Занимается разработкой CRM для малого и среднего бизнеса. Задача дается "как есть". Т.е. я не могу ответить "что думала компания" в этой задаче. В ходе решения разрешается пользоваться интернетом и поисковой системой. Время на решения - до 20 минут. Позиция - junior frontend dev.

Задача


Почтовые программы представляют email в двух стандартах - с учетом имени, которое пользователь ввел в настройках почтового ящика:

Volodimir Singapuk <singapuk.e03@gmail.com>

и просто email, так:

singapuk.e03@gmail.com

Задача: написать решение которое может принимать строку в одном из двух форматов и возвращать только email. Уточняем:

Приняли Volodimir Singapuk <singapuk.e03@gmail.com>

возвратили singapuk.e03@gmail.com

Приняли singapuk.e03@gmail.com

Возвратили singapuk.e03@gmail.com


Выполним анализ задачи. Условия не полные, поэтому не будем додумывать задачу, задача сводится к поиску угловых кавычек и, если он есть, возврату текста между ними. Валидации email выходит за рамки текущей задачи.

Как решали задачу кандидаты

После того как собеседование прошли несколько десятков человек, можно заметить интересную тенденцию. Вначале все бросались решать задачу с помощью регулярных выражений. Действительно, с помощью поиска и онлайн инструментов можно быстро получить текст с угловыми скобками <singapuk.e03@gmail.com>, а дальше становилось все интереснее... Кандидат, после первого успеха, начинает искать как получить текст между тегами с помощью регулярных выражений, и ничего не находил. Спустя 10 минут поиска (не забывайте - общее время 20 минут), в ход шли методы работы со строкой и текст просто вырезался. Потом кандидат смотрел на код, понимал, что он не очень красив и переделывал код на просто работу со строкой. Успешно задачу только регулярными выражениями решили только 3 кандидата.

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

Решаем методами работы со строками JS

Итак, у нас есть строка и по ней нужно провести поиск угловых скобок. Если в тексте есть "<" то можно искать проводить вырезание текста. Давайте сделаем.

let index = email.indexOf('<');

если index не равен -1, то нужно вырезать подстроку, которая отвечает за email - с символа следующего ЗА index (что логично, ведь мы получили индекс угловой скобки). Вырезать подстроку будем до самого конца строки, за исключением последнего (символа ">").

email.substring(index + 1, email.length - 1);

в результате решение выглядит так:

const str1 = 'Volodimir Singapuk <singapuk.e03@gmail.com>';

const trimEmail = email => {
    let index = email.indexOf('<');
    if ( index !== -1) {
        return email.substring(index + 1, email.length - 1);
    }
    return email;
}

console.log(trimEmail(str1));

Проверяем, убеждаемся, что все решение работает с двумя видами email представлений. И переходим к следующему решению.

Дополнение. По функции видно, что здесь и не нужна валидация email. Если проводить валидацию, то логично оформить ее отдельной функцией, которая будет срабатывать до функции trimEmail.

Вырезаем текст между символами с помощью регулярных выражений

Теперь - регулярки. Получить email из строки вида:
Volodimir Singapuk <singapuk.e03@gmail.com>
довольно просто. Для этого можно просто ввести <\S+>. Расшифруем - угловые скобки думаю понятно, \S символьный класс, который обозначает непробельный символ. А символ плюс + квантификатор, который показывает что непробельный символ встречается минимум один раз или больше.

Проверить данное выражение можно на сервисе regex101.com.

Пока все выглядит просто. Но проблема в том, что мы получаем email с угловыми скобками. А вот получить текст между нужных символов значительно сложнее. Нужно знать, что искать. И многие кандидаты на собеседовании тратили время на поиск и не находили результата. Действительно, искать "опережающие и ретроспективные проверки" будет не каждый. Да, в регулярных выражениях есть возможность искать ПОСЛЕ символа и ДО символа. И называется это страшным выражением "опережение и ретроспектива".

Если упростить, то чтобы пометить символ после которого вы хотите вести поиск, нужно ввести паттерн вида ?<=символ, обычно символ пишут с экранированием, т.е. так ?<=\символ. А символ ДО которого нужно искать пишут паттерном ?=символ, или с экранированием ?=\символ. Если применить данные знания к нашей задаче то придется написать следующее регулярное выражение:

(?<=\<)(\S+)(?=\>)

т.е. ищем между < > любую строку не пробельных символов. Проверить можно также на regex101.

Самое сложное мы сделали. Теперь нужно протестировать строку на совпадение с регулярным выражением. Для проверки есть два метода в JavaScript, это test() и match(). Первый метод подходит для тестирования и просто отвечает есть или нет совпадение. А второй - возвращает массив совпадений. Поскольку у нас задача вернуть вырезанный тект - то идеально подходит второй метод. Решаем. Вначале введем регулярку:

const regexp = /(?<=\<)(\S+)(?=\>)/g;

регулярное выражение в JavaScript вводиться между / /. Также добавим флаг g, потому что match() имеет два режима работы. С флагом g он возвращает массив совпадений (то что нам нужно), а без флага - сырые данные. И выполняем метод:

const matches = email.match(regexp);));

Далее проверяем, если найдено совпадение то будет возвращен массив, если нет - null. И решение становится такое:

const trimEmail = email => {
	const regexp = /(?<=\<)(\S+)(?=\>)/g;
	const matches = email.match(regexp);
    if (mathes !== null) return matches[0];
    return email;
}

console.log(trimEmail(str1));

Проверяйте и убедитесь, что код работает корректно с двумя видами email.

Вот такая интересная задача, довольно простая, но позволяет понять логику соискателя.

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

Скачать код можно тут. Также рекомендую посмотреть, как решали задачу в телеграмм канале ItGid.

Загрузить файл с кодом: Download

Статьи

Подсвечиваем НЕ ЛАТИНСКИЕ СИМВОЛы в коде и тексте
Тотальное руководство по элементу Select в JavaScript
Кнопка "Показать пароль" на JavaScript + анимация