Чтобы обратить строку «на месте», не используя временной строки, используйте шаблон функции reverse из заголовочного файла :

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, но начинает с конца строки и движется к ее началу. Для больших строк или большого количества строк обращение может оказаться очень дорогостоящим, так что при возможности избегайте его.

<p>4.6. Разделение строки</p>Проблема

Требуется разделить строку с разделителями на несколько строк. Например, может потребоваться разделить строку "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()));

 }

}

Логика при этом не меняется.

Однако обратите внимание, что между двумя последними угловыми скобками в последней строке заголовка функции добавлен один пробел. Это требуется для того, чтобы сказать компилятору, что это не оператор сдвига вправо.

Перейти на страницу:

Похожие книги