Кстати, когда потребуется узнать, пуста ли строка, не сравнивайте ее размер с нулем, а просто вызовите метод empty
. Это метод, который возвращает истину, если длина строки равна нулю.
4.5. Обращение строк
Требуется обратить (реверсировать) строку.
Чтобы обратить строку «на месте», не используя временной строки, используйте шаблон функции reverse из заголовочного файла <algorithm>
:
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
.
#include <string>
#include <vector>
#include <functional>
#include <iostream>
using namespace std;
void split(const string& s, char c, vector<string>& 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<string> v;
string s = 'Account Name|Address 1|Address 2 |City';
split(s, '|', v);
for (int i = 0; i < v.size(); ++i) {
cout << v[i] << '
';
}
}
Превращение приведенного выше примера в шаблон функции, принимающий любой тип символов, тривиально — просто параметризуйте тип символов и замените случаи использования string
на basic_string<T>
.
template<typename T>
void split(const basic_string<T>& s, T c,
vector<basic_string<T> >& v) {
basic_string<T>::size_type i = 0;
basic_string<T>::size_type j = s.find(c);
while (j != basic_string<T>::npos) {
v.push_back(s.substr(i, j-i));
i = ++j;
j = s.find(c, j);
if (j == basic_string<T>::npos)
v.push back(s.substr(i, s.length()));
}
}
Логика при этом не меняется.
Однако обратите внимание, что между двумя последними угловыми скобками в последней строке заголовка функции добавлен один пробел. Это требуется для того, чтобы сказать компилятору, что это не оператор сдвига вправо.