Небольшие, но важные функции

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Будущих студентов курса "C++ Developer. Professional" приглашаем принять участие в открытом уроке "Backend на современном С++".

А пока делимся традиционным переводом материала.


Начиная с C++20 в несколько стандартных контейнеров, включая std::map, std::set и std::string, были добавлены некоторые очень полезные функции для поиска. Необходимость в них существовала уже в течении достаточно долгого времени, и мне приятно видеть, что комитет наконец признал их важность. Надеюсь, это только начало серии замечательных дополнений.

Map и set

Типовая операция при работе с map — проверить, существует ли конкретный ключ. Как это сделать в C++17? Все просто:

std::map<int, std::string> m{ {1, "one"}, {2, "two"}, {3, "three"} };
 
if (m.find(1) != m.end())
{
   std::cout << "key found!\n";
}

Хотя это может быть достаточно просто, это отнюдь совсем не удобно для пользователя. По этой причине многие пишут свою собственную функцию contains(), которая принимает map и ключ и возвращает логическое значение, указывающее, содержит ли map ключ. В C++20 это больше не нужно, т.к. std::map имеет родной метод contains().

std::map<int, std::string> m{ {1, "one"}, {2, "two"}, {3, "three"} };
 
if (m.contains(1))
{
   std::cout << "key found!\n";
}

То же верно и для std::set

std::set<int> s{ 1, 2, 3 };
if (s.contains(1))
{
   std::cout << "key found!\n";
}

Даже больше, в C++20 функция contains() была добавлена ​​к целому ряду типов:

  • std::map

  • std::multimap

  • std::unordered_map

  • std::unordered_multimap

  • std::set

  • std::multiset

  • std::unordered_set

  • std::unordered_multiset

Строки

Похожая проблема актуальна и для строк. Иногда нам нужно узнать, содержит ли строка другую строку. Вот как это делается в C++17:

std::string text{"The quick brown fox jumps over the lazy dog"};
 
if (text.find("fox") != std::string::npos)
{
   std::cout << "fox found!\n";
}

Частный случай, связанный со строками, — это поиск подстроки в начале и в конце строки. Поиск в начале относительно прост:

if (text.find("The quick") == 0)
{
   std::cout << "right start\n";
}

Но для поиска в конце требуется вспомогательная функция. Возможная реализация такова:

bool ends_with(std::string const & text, std::string const & substr)
{
   if (substr.size() > text.size()) return false;
   return std::equal(text.begin() + text.size() - substr.size(), text.end(), substr.begin());
}

Что можно использовать следующим образом:

if (ends_with(text, "lazy dog"))
{
   std::cout << "right end\n";
}

(Примечание: Вы можете найти альтернативные реализации этой функции здесь)

C++20 значительно упростил ситуацию, где std::basic¨C16Cstring¨C17Cwith() и ends¨C18Cwith("The quick"))

if (text.starts_with("The quick"))
{
   std::cout << "right start\n";
}
 
if(text.ends_with("lazy dog"))
{
   std::cout << "right end\n";
}

Однако в C++20 есть достаточно большое упущение: функция для проверки того, содержит ли строка подстроку. Во время последнего заседания комитета ISO C++, такой метод был добавлен в C++23 (P1679). Это позволит нам написать следующее:

if (text.contains("fox"))
{
   std::cout << "fox found!\n";
}

Именно так мы всегда и хотели писать код.

Но…

Вы должны помнить, что эти новые строковые функции чувствительны к регистру. Они не принимают предикат, позволяющий настроить способ выполнения поиска. Следовательно, если вам нужно выполнить поиск без учета регистра, вам все равно нужно будет реализовать это самостоятельно. Возможные реализации contains(), startwith() и endwith(), которые выполняют поиск без учета регистра, показаны ниже:

bool contains_ci(std::string const & text, std::string const & substr)
{
   if (substr.length() > text.length()) return false;
 
   auto it = std::search(
      text.begin(), text.end(),
      substr.begin(), substr.end(),
      [](char ch1, char ch2) { 
         return std::toupper(ch1) == std::toupper(ch2); });
 
   return it != text.end();
}
 
bool starts_with_ci(std::string const& text, std::string const& substr)
{
   if (substr.length() > text.length()) return false;
 
   auto it = std::search(
      text.begin(), text.begin() + substr.length(),
      substr.begin(), substr.end(),
      [](char ch1, char ch2) {
         return std::toupper(ch1) == std::toupper(ch2); });
 
   return it == text.begin();
}
 
bool ends_with_ci(std::string const& text, std::string const& substr)
{
   if (substr.length() > text.length()) return false;
 
   auto it = std::search(
      text.rbegin(), text.rbegin() + substr.length(),
      substr.rbegin(), substr.rend(),
      [](char ch1, char ch2) {
         return std::toupper(ch1) == std::toupper(ch2); });
 
   return it == text.rbegin();
}

А использовать их можно следующим образом:

if (contains_ci(text, "FOX"))
{
   std::cout << "fox found!\n";
}
 
if (starts_with_ci(text, "THE QUICK"))
{
   std::cout << "right start\n";
}
 
if (ends_with_ci(text, "LAZY DOG"))
{
   std::cout << "right end\n";
}

Узнать подробнее о курсе "C++ Developer. Professional".

Записаться на открытый урок "Backend на современном С++".


Читать ещё:

  • Полиморфные аллокаторы C++17

Источник: https://habr.com/ru/company/otus/blog/531122/


Интересные статьи

Интересные статьи

Мне было необходимо делать 2 раза в сутки бэкап сайта на «1С-Битрикс: Управление сайтом» (файлов и базы mysql) и хранить историю изменений за 90 дней. Сайт расположен на VDS под уп...
Как-то у нас исторически сложилось, что Менеджеры сидят в Битрикс КП, а Разработчики в Jira. Менеджеры привыкли ставить и решать задачи через КП, Разработчики — через Джиру.
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.
В 2019 году люди знакомятся с брендом, выбирают и, что самое главное, ПОКУПАЮТ через интернет. Сегодня практически у любого бизнеса есть свой сайт — от личных блогов, зарабатывающих на рекламе, до инт...
Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row si...