Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
std::reverse(s.begin(), s.end());
reverse
работает очень просто: она изменяет диапазон, переданный ей, так, что его порядок меняется на обратный оригинальному. Время, необходимое для этого, линейно зависит от длины диапазона.
В случае, если требуется скопировать строку в другую строку, но в обратном порядке символов, используйте реверсивные итераторы, как здесь:
std::string s = "Los Angeles";
std::string rs;
rs.assign(s.rbegin(), s.rend());
rbegin
и rend
возвращают реверсивные итераторы. Реверсивные итераторы ведут себя так, как будто они просматривают последовательность в обратном порядке. rbegin
возвращает итератор, который указывает на последний элемент, a rend
возвращает итератор, указывающий на позицию перед первым элементом. Это в точности обратно тому, что делают begin
и end
.
Но должны ли вы обращать строку? С помощью rbegin
и rend
для обратной строки можно использовать все методы или алгоритмы, работающие с диапазонами итераторов. А если требуется выполнить поиск в строке, то можно использовать rfind
, которая делает то же, что и find
, но начинает с конца строки и движется к ее началу. Для больших строк или большого количества строк обращение может оказаться очень дорогостоящим, так что при возможности избегайте его.
4.6. Разделение строки
Требуется разделить строку с разделителями на несколько строк. Например, может потребоваться разделить строку "Name|Address|Phone"
на три отдельных строки — "Name"
, "Address"
и "Phone"
, удалив при этом разделитель.
Для перехода от одного вхождения разделителя к следующему используйте метод find
класса basic_string
, а для копирования каждой подстроки используйте substr
. Для хранения результатов используйте любую стандартную последовательность. Пример 4.10 использует vector
.
Пример 4.10. Разделение строки с разделителями
#include
#include
#include
#include
using namespace std;
void split(const string& s, char c, vector& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
int main() {
vector v;
string s = "Account Name|Address 1|Address 2 |City";
split(s, '|', v);
for (int i = 0; i < v.size(); ++i) {
cout << v[i] << '\n';
}
}
Превращение приведенного выше примера в шаблон функции, принимающий любой тип символов, тривиально — просто параметризуйте тип символов и замените случаи использования string
на basic_string
.
template
void split(const basic_string& s, T c,
vector >& v) {
basic_string::size_type i = 0;
basic_string::size_type j = s.find(c);
while (j != basic_string::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == basic_string::npos)
v.push back(s.substr(i, s.length()));
}
}
Логика при этом не меняется.
Однако обратите внимание, что между двумя последними угловыми скобками в последней строке заголовка функции добавлен один пробел. Это требуется для того, чтобы сказать компилятору, что это не оператор сдвига вправо.
Пример 4.10 разбивает строку с помощью простого алгоритма. Начиная с начала строки, он ищет первое вхождение разделителя с, а затем считает, что все, что стоит после начала строки или предыдущего найденного вхождения и до этого вхождения, является очередным фрагментом текста. Для поиска первого вхождения символа в оригинальной строке string
пример использует метод find
, а для копирования символов диапазона в новую string
, помещаемую в vector
, — метод substr
. Это тот же самый принцип, который используется в функциях разбиения строк большинства скриптовых языков и является специальным случаем разделения строки текста на лексемы (tokenizing) , описываемого в рецепте 4.7.
Разделение строки, использующей единственный символ-разделитель, является очень распространенной задачей, и неудивительно, что ее решение есть в библиотеке Boost String Algorithms. Оно просто в использовании. Чтобы увидеть, как разделить строку с помощью функции split
из Boost, посмотрите на пример 4.11.
Пример 4.11. Разделение строки с помощью Boost
#include
#include
#include
#include
using namespace std;
using namespace boost;
int main() {
string s = "one,two,three,four";
list results;
split(results, s, is_any_of(",")); // Обратите внимание - это boost::split
for (list::const_iterator p = results.begin();
p != results.end(); ++p) {
cout << *p << endl;
}
}
split
— это шаблон функции, принимающий три аргумента. Он объявлен вот так.
template
Seq& split(Seq& s, Coll& c, Pred p,
token_compress_mode_type e = token_compress_off);
Seq
, Coll
и Pred
представляют типы результирующей последовательности, входной коллекции и предиката, используемого для определения, является ли очередной объект разделителем. Аргумент последовательности — это последовательность, определенная по стандарту C++, содержащая нечто, что может хранить части того, что находится во входной коллекции. Так, например, в примере 4.11 был использован list
, но вместо него можно было бы использовать и vector
. Аргумент коллекции — это тип входной последовательности. Коллекция — это нестандартная концепция, которая похожа на последовательность, но с несколько меньшими требованиями (за подробностями обратитесь к документации по Boost по адресу www.boost.org ). Аргумент предиката — это объект унарной функции или указатель на функцию, которая возвращает bool
, указывающий, является ли ее аргумент разделителем или нет. Она вызывается для каждого элемента последовательности в виде f(*it)
, где it
— это итератор, указывающий на элемент последовательности.
is_any_of
— это удобный шаблон функции, поставляющийся в составе String Algorithms, которая облегчает жизнь при использовании нескольких разделителей. Он конструирует объект унарной функции, которая возвращает true
, если переданный ей аргумент является членом набора. Другими словами:
bool b = is_any_of("abc")('a'); // b = true
Это облегчает проверку нескольких разделителей, не требуя самостоятельного написания объекта функции.
4.7. Разбиение строки на лексемы
Требуется разбить строку на части, используя набор разделителей.
Для перебора элементов строки и поиска места нахождения следующих лексем и не-лексем используйте методы find_first_of
и first_first_not_of
. Пример 4.12 представляет простой класс StringTokenizer
, выполняющий эту задачу.
Интервал:
Закладка: