return (count_ = n);
}
bool hasMoreTokens() { return(begin_ != end_); }
void nextToken(string& s) {
if (begin_ != string::npos && end_ != string::npos) {
s = str_.substr(begin_, end_-begin_);
begin_ = str_.find_first_not_of(delim_, end_);
end_ = str_.find_first_of(delim_, begin_);
} else if (begin_ != string::npos && end_ == string::npos) {
s = str_.substr(begin_, str_.length()-begin_);
begin_ = str_.find_first_not_of(delim_, end_);
}
}
private:
StringTokenizer() {}
string delim_;
string str_;
int count_;
int begin_;
int end_;
};
int main() {
string s = ' razzle dazzle giddyup ';
string tmp;
StringTokenizer st(s);
cout << 'Здесь содержится' << st.countTokens() << ' лексемы.
';
while (st.hasMoreTokens()) {
st.nextToken(tmp);
cout << 'token = ' << trap << '
';
}
}
Разбиение строки с четко определенной структурой, как в примере 4.10, конечно, хорошо, но не все так просто. Предположим, что, вместо того чтобы просто разделить строку на основе единственного разделителя, требуется StringTokenizer
(аналогичного стандартному классу Java™ с таким же именем) для C ++, который принимает символы-разделители, но по умолчанию использует пробелы.
Наиболее важные строки в StringTokenizer
используют методы find_first_of
и find_first_not_of
шаблона класса basic_string
. Их описание и примеры использования даны в рецепте 4.9. Пример 4.12 дает такой вывод.
Здесь содержится 3 лексемы.
token = razzle
token = dazzle
token = giddyu
p
StringTokenizer
— это более гибкая форма функции split
из примера 4.10. Он поддерживает свое состояние, так что можно просто последовательно переходить с одной лексемы на другую, не разбивая вначале всю строку на части. Также есть возможность подсчитать число лексем.
В StringTokenizer
можно внести пару усовершенствований. Во-первых, для простоты StringTokenizer
написан так, что он работает только с простыми строками — другими словами, строками из узких символов. Если требуется, чтобы один и тот же класс работал как с узкими, так и с широкими символами, параметризуйте тип символов, как это сделано в предыдущих рецептах. Другим улучшением является расширение StringTokenizer
так, чтобы он обеспечивал более дружественное взаимодействие с последовательностями и был более гибок. Вы всегда можете сделать это сами, а можете использовать имеющийся класс разбиения на лексемы. Проект Boost содержит класс tokenizer
, делающий все это. За подробностями обратитесь к
Рецепт 4.24.
4.8. Объединение нескольких строк
Имея последовательность строк, такую как вывод примера 4.10, вам требуется объединить их в одну длинную строку, возможно, с разделителями.
В цикле переберите всю последовательность строк и добавьте каждую из них в выходную строку. В качестве входа можно обрабатывать любую стандартную последовательность. Пример 4.13 использует vector
из элементов типа string
.
#include <string>
#include <vector>
#include <iostream>
using namespace std;
void join(const vector<string>& v, char c, string& s) {
s.clear();
for (vector<string>::const_iterator p = v.begin();
p ! = v.end(); ++p) {
s += *p;
if (p != v.end() - 1) s += c;
}
}
int main() {
vector<string> v;
vector<string> v2;
string s;
v.push_back(string('fее'));
v.push_back(string('fi'));
v.push_back(string('foe'));