Части begin
end
обозначают нашу входную строку, по которой итератор, работающий с токенами регулярного выражения, будет итерировать и искать все ссылки. link_re
— это, конечно, сложное регулярное выражение, созданное нами для поиска ссылок. Часть {1, 2}
— еще один непонятный фрагмент. Он дает итератору команду опускать полное совпадение и возвращать группу 1, затем инкрементировать итератор и возвращать группу 2, а позже, после очередной операции инкремента, находить следующее совпадение в строке. Это разумное поведение освобождает нас от необходимости писать ненужные строки кода.Давайте рассмотрим еще один пример. Представим регулярное выражение "a(b*)(c*)"
a
, после которого идет ноль или больше символов b
, а затем — ноль или больше символов c
:const string s {" abc abbccc "};
const regex re {"a(b*)(c*)"};
sregex_token_iterator it {begin(s), end(s), re, {1, 2}};
print( *it ); // выводит b
++it;
print( *it ); // выводит c
++it;
print( *it ); // выводит bb
++it;
print( *it ); // выводит ccc
Существует также класс std::regex_iterator
Удобный и красивый динамический вывод чисел на экран в зависимости от контекста
В предыдущем примере было показано, как отформатировать выходные данные с помощью потоков вывода. Во время решения данной задачи мы узнали следующее:
□ большая часть манипуляторов являются стойкими, поэтому нужно отменять их действие, чтобы не пересечься с другим несвязанным кодом, который также выводит данные на экран;
□ создавать длинные цепочки манипуляторов ввода/вывода, чтобы вывести несколько переменных с конкретным форматированием, может быть утомительно, а код получится не очень читабельным.
По этим причинам многие пользователи не любят потоки ввода/вывода и даже в С++ все еще применяют функцию print
Ниже мы увидим, как форматировать типы динамически, не прибегая к чрезмерно большому количеству манипуляторов ввода/вывода.
Как это делается
В этом примере мы реализуем класс format_guard
1. Сначала включим некоторые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
using namespace std;
2. Вспомогательный класс, очищающий состояние форматирования для потоков, называется format_guard
std::cout
в момент создания объекта. Его деструктор восстанавливает их состояние на момент вызова конструктора. Это, по сути, отменяет все настройки форматирования, примененные между вызовами данных методов.class format_guard {
decltype(cout.flags()) f {cout.flags()};
public:
~format_guard() { cout.flags(f); }
};
3. Еще один небольшой вспомогательный класс называется scientific_type
template
struct scientific_type {
T value;
explicit scientific_type(T val) : value{val} {}
};
4. Можно определить собственные настройки форматирования для любого типа, который ранее был обернут в scientific_type
>>
потоковая библиотека будет выполнять совершенно другой код при выводе подобных типов. Таким образом, можно выводить научные значения в научном представлении с плавающей точкой, в верхнем регистре и явным префиксом +
, если они имеют положительные значения. Кроме того, мы используем наш класс format_guard
, чтобы очистить все настройки при выходе из функции:template
ostream& operator<<(ostream &os, const scientific_type
format_guard _;
os << scientific << uppercase << showpos;
return os << w.value;
}
5. В функции main
format_guard
. Откроем новую область видимости, получим экземпляр класса, а затем применим некоторые флаги форматирования к потоку вывода std::cout
:int main()
{
{