cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
// Вложенные вызовы функций обрезки
s1 = " ****Обрезка!*** ";
s2 = trim_copy_if(trim_copy(s1), is_any_of("*"));
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
}
Пример 4.5 демонстрирует, как использовать функции обрезки строк Boost. Обычно способ их использования понятен из их названия, так что я не буду вдаваться в описания более подробные, чем даны в табл. 4.1. Единственная функция, имеющаяся в этом примере и отсутствующая в таблице, — это is_any_of. Это шаблон функции, который возвращает объект функции-предиката, используемый функциями серии trim_if. Она используется, когда требуется обрезать набор символов. Также есть аналогичная функция классификации, которая называется is_from_range и принимает два аргумента и возвращает унарный предикат, который возвращает истину, когда символ находится в заданном диапазоне. Например, чтобы обрезать в строке символы с а до d, требуется сделать что-то, похожее на следующее.
s1 = "abcdXXXabcd";
trim_if(s1, is_from_range('a', 'd'));
cout << "s1 = " << s1 << endl; // Теперь s1 = XXX
Заметьте, что эта конструкция чувствительна к регистру, так как диапазон от а до d не включает заглавных версий этих букв.
4.3. Хранение строк в последовательности
Требуется сохранить набор строк в виде последовательности, которая ведет себя как массив.
Для хранения строк в виде массива используйте vector. Пример 4.6 показывает простой образец.
#include
#include
#include
using namespace std;
int main() {
vector
string s = "one";
v.push_back(s);
s = "two";
v.push_back(s);
s = "three";
v.push_back(s);
for (int i = 0; i < v.size(); ++i) {
cout << v[i] << "\n";
}
}
vector использует для произвольного доступа семантику массива (а также делает много другого), так что он прост и понятен в использовании. Однако vector — это только одна из многих последовательностей стандартной библиотеки. Чтобы узнать об этом побольше, читайте дальше.
vector — это динамическая последовательность объектов, которая предоставляет произвольный доступ с помощью оператора в стиле массивов operator[]. Метод push_back при помощи копирующего конструктора копирует свой аргумент, добавляет копию в последний элемент вектора и увеличивает его размер на единицу. pop_back выполняет обратную операцию, удаляя последний элемент. Вставка и удаление элементов в конце вектора занимает постоянное время, а время вставки и удаления элементов в середине вектора линейно зависит от его размера. Это основы векторов. Кроме этого, они умеют еще много чего.
В большинстве случаев vector должен быть первым выбором вместо массива в стиле С. Во-первых, их размеры изменяются динамически, что означает, что эти размеры увеличиваются по мере необходимости. Не требуется проводить каких-либо исследований для выбора оптимального размера статического массива, как в случае с массивами С, — vector растет по мере надобности, а при необходимости может быть увеличен или уменьшен вручную. Во-вторых, vector при использовании метода at (но не при использовании operator[]) предлагает проверку границ, так что при ссылке на несуществующий индекс программа не обрушится и не продолжит выполнение с неверными данными. Посмотрите на пример 4.7, Он показывает, как работать с индексами, выходящими за границы массива.
#include
#include
#include
using namespace std;
int main() {
char carr[] = {'a', 'b', 'c', 'd', 'e'};
cout << carr[100000] << '\n'; // Оп, кто знает, что дальше
// произойдет
vector
v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');
v push_back('e');
try {
cout << v.at(10000) << "\n"; // at проверяет границы и выбрасывает
} catch(out_of_range& е) { // out_of_range, если произошел выход за них
cerr << e.what() << '\n';
}
}