Как мне перебрать слова строки?
Я пытаюсь перебрать слова строки.
Можно предположить, что строка состоит из слов, разделенных пробелами.
Обратите внимание, что меня не интересуют строковые функции Си или подобные манипуляции /доступ к символам. Кроме того, в своем ответе просьба отдавать предпочтение элегантности, а не эффективности.
Лучшее решение, которое у меня есть сейчас:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
Есть ли более элегантный способ сделать это?
29 ответов
Для чего стоит, вот еще один способ извлечь токены из входной строки, опираясь только на стандартные библиотечные средства. Это пример силы и элегантности дизайна STL.
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
int main() {
using namespace std;
string sentence = "And I feel fine...";
istringstream iss(sentence);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
ostream_iterator<string>(cout, "\n"));
}
Вместо копирования извлеченных токенов в выходной поток их можно вставить в контейнер, используя тот же общий алгоритм copy
.
vector<string> tokens;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(tokens));
... или создайте vector
напрямую:
vector<string> tokens{istream_iterator<string>{iss},
istream_iterator<string>{}};
Я использую это, чтобы разделить строку разделителем. Первый помещает результаты в предварительно построенный вектор, второй возвращает новый вектор.
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
Обратите внимание, что это решение не пропускает пустые токены, поэтому следующие найдут 4 элемента, один из которых пуст:
std::vector<std::string> x = split("one:two::three", ':');
Возможное решение с использованием Boost может быть следующим:
#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));
Этот подход может быть даже быстрее, чем подход stringstream
. А поскольку это универсальная функция шаблона, ее можно использовать для разделения других типов строк (wchar и т. Д. Или UTF-8) с использованием всех видов разделителей.
Подробнее см. документацию .
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::string str("Split me by whitespaces");
std::string buf; // Have a buffer string
std::stringstream ss(str); // Insert the string into a stream
std::vector<std::string> tokens; // Create vector to hold our words
while (ss >> buf)
tokens.push_back(buf);
return 0;
}
Для тех, с кем не очень удобно жертвовать всей эффективностью ради размера кода и рассматривать «эффективный» как тип элегантности, следующее должно быть приятно: .):
template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
const std::string& delimiters = " ", bool trimEmpty = false)
{
std::string::size_type pos, lastPos = 0, length = str.length();
using value_type = typename ContainerT::value_type;
using size_type = typename ContainerT::size_type;
while(lastPos < length + 1)
{
pos = str.find_first_of(delimiters, lastPos);
if(pos == std::string::npos)
{
pos = length;
}
if(pos != lastPos || !trimEmpty)
tokens.push_back(value_type(str.data()+lastPos,
(size_type)pos-lastPos ));
lastPos = pos + 1;
}
}
Обычно я выбираю типы std::vector<std::string>
в качестве второго параметра (ContainerT
) ... но list<>
намного быстрее, чем vector<>
для случаев, когда прямой доступ не требуется, и вы даже можете создать свой собственный класс строки и использовать что-то вроде std::list<subString>
где subString
не делает никаких копий для невероятного увеличения скорости.
Это более чем в два раза быстрее, чем самый быстрый токен на этой странице, и почти в 5 раз быстрее, чем некоторые другие. Также с идеальными типами параметров вы можете исключить все копии строк и списков для дополнительного увеличения скорости.
Кроме того, он не выполняет (крайне неэффективный) возврат результата, а скорее передает токены в качестве ссылки, что также позволяет вам создавать токены с использованием нескольких вызовов, если вы того пожелаете.
Наконец, он позволяет указать, следует ли обрезать пустые токены из результатов с помощью последнего необязательного параметра.
Все, что ему нужно, это std::string
... остальное необязательно. Он не использует потоки или библиотеку надстройки, но достаточно гибок, чтобы иметь возможность естественным образом принимать некоторые из этих внешних типов.
Вот еще одно решение. Он компактен и достаточно эффективен:
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
tokens.push_back(text.substr(start, end - start));
start = end + 1;
}
tokens.push_back(text.substr(start));
return tokens;
}
Он может быть легко шаблонизирован для работы с разделителями строк, широкими строками и т. д.
Обратите внимание, что разделение ""
приводит к появлению одной пустой строки и разделению ","
(т.е. sep) приводит к двум пустым строкам.
Он также может быть легко расширен для пропуска пустых токенов:
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
if (end != start) {
tokens.push_back(text.substr(start, end - start));
}
start = end + 1;
}
if (end != start) {
tokens.push_back(text.substr(start));
}
return tokens;
}
Если желательно разделение строки по нескольким разделителям при пропуске пустых токенов, можно использовать эту версию:
std::vector<std::string> split(const std::string& text, const std::string& delims)
{
std::vector<std::string> tokens;
std::size_t start = text.find_first_not_of(delims), end = 0;
while((end = text.find_first_of(delims, start)) != std::string::npos)
{
tokens.push_back(text.substr(start, end - start));
start = text.find_first_not_of(delims, end);
}
if(start != std::string::npos)
tokens.push_back(text.substr(start));
return tokens;
}
Это мой любимый способ перебора строки. Вы можете делать все, что вы хотите для каждого слова.
string line = "a line of text to iterate through";
string word;
istringstream iss(line, istringstream::in);
while( iss >> word )
{
// Do something on `word` here...
}
Это похоже на вопрос о переполнении стека. токенизировать строку в C ++? .
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
int main(int argc, char** argv)
{
string text = "token test\tstring";
char_separator<char> sep(" \t");
tokenizer<char_separator<char>> tokens(text, sep);
for (const string& t : tokens)
{
cout << t << "." << endl;
}
}
Мне нравится следующее, потому что это помещает результаты в вектор, поддерживает строку в качестве разделителя и дает контроль над сохранением пустых значений. Но это выглядит не так хорошо.
#include <ostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
vector<string> split(const string& s, const string& delim, const bool keep_empty = true) {
vector<string> result;
if (delim.empty()) {
result.push_back(s);
return result;
}
string::const_iterator substart = s.begin(), subend;
while (true) {
subend = search(substart, s.end(), delim.begin(), delim.end());
string temp(substart, subend);
if (keep_empty || !temp.empty()) {
result.push_back(temp);
}
if (subend == s.end()) {
break;
}
substart = subend + delim.size();
}
return result;
}
int main() {
const vector<string> words = split("So close no matter how far", " ");
copy(words.begin(), words.end(), ostream_iterator<string>(cout, "\n"));
}
Конечно, в Boost есть ---- +: = 1 =: + ---- , который работает частично так. И, если под «пробелами» вы действительно подразумеваете любой тип пробелов, использование расщепления Boost с split()
прекрасно работает.
STL еще не имеет такого метода.
Однако вы можете воспользоваться strtok()
с помощью std::string::c_str()
или вы можете написать свой собственный. Вот пример кода, который я обнаружил после быстрого поиска в Google ( "STL string split" ):
void Tokenize(const string& str,
vector<string>& tokens,
const string& delimiters = " ")
{
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
Взято из: http: //oopweb. ком /CPP /Документы /CPPHOWTO /Volume /C ++ программирование-HOWTO-7.html
Если у вас есть вопросы по поводу примера кода, оставьте комментарий, и я объясню.
И только потому, что он не реализует typedef
, называемый итератором, или не перегружает <<
оператор не означает, что это плохой код. Я использую функции C довольно часто. Например, printf
и scanf
оба работают быстрее, чем std::cin
и std::cout
(значительно), fopen
намного более удобен для двоичных типов, и они также имеют тенденцию создавать меньшие EXE-файлы.
Не продавайте по этой сделке «Элегантность над производительностью» .
Вот функция разделения, которая:
- является общим
- использует стандарт C ++ (без повышения)
- принимает несколько разделителей
-
игнорирует пустые токены (их можно легко изменить)
template<typename T> vector<T> split(const T & str, const T & delimiters) { vector<T> v; typename T::size_type start = 0; auto pos = str.find_first_of(delimiters, start); while(pos != T::npos) { if(pos != start) // ignore empty tokens v.emplace_back(str, start, pos - start); start = pos + 1; pos = str.find_first_of(delimiters, start); } if(start < str.length()) // ignore trailing delimiter v.emplace_back(str, start, str.length() - start); // add what's left of the string return v; }
Пример использования:
vector<string> v = split<string>("Hello, there; World", ";,");
vector<wstring> v = split<wstring>(L"Hello, there; World", L";,");
У меня есть 2-х строчное решение этой проблемы:
char sep = ' ';
std::string s="1 This is an example";
for(size_t p=0, q=0; p!=s.npos; p=q)
std::cout << s.substr(p+(p!=0), (q=s.find(sep, p+1))-p-(p!=0)) << std::endl;
Тогда вместо печати вы можете поместить его в вектор.
Еще один гибкий и быстрый способ
template<typename Operator>
void tokenize(Operator& op, const char* input, const char* delimiters) {
const char* s = input;
const char* e = s;
while (*e != 0) {
e = s;
while (*e != 0 && strchr(delimiters, *e) == 0) ++e;
if (e - s > 0) {
op(s, e - s);
}
s = e + 1;
}
}
Использовать его с вектором строк (Правка: поскольку кто-то указал не наследовать классы STL ... hrmf;)):
template<class ContainerType>
class Appender {
public:
Appender(ContainerType& container) : container_(container) {;}
void operator() (const char* s, unsigned length) {
container_.push_back(std::string(s,length));
}
private:
ContainerType& container_;
};
std::vector<std::string> strVector;
Appender v(strVector);
tokenize(v, "A number of words to be tokenized", " \t");
Вот и все! И это только один из способов использовать токенизатор, например, как просто считать слова:
class WordCounter {
public:
WordCounter() : noOfWords(0) {}
void operator() (const char*, unsigned) {
++noOfWords;
}
unsigned noOfWords;
};
WordCounter wc;
tokenize(wc, "A number of words to be counted", " \t");
ASSERT( wc.noOfWords == 7 );
Ограничено воображением;)
Вот простое решение, которое использует только стандартную библиотеку регулярных выражений
#include <regex>
#include <string>
#include <vector>
std::vector<string> Tokenize( const string str, const std::regex regex )
{
using namespace std;
std::vector<string> result;
sregex_token_iterator it( str.begin(), str.end(), regex, -1 );
sregex_token_iterator reg_end;
for ( ; it != reg_end; ++it ) {
if ( !it->str().empty() ) //token could be empty:check
result.emplace_back( it->str() );
}
return result;
}
Аргумент regex позволяет проверять наличие нескольких аргументов (пробелы, запятые и т. д.)
Я обычно проверяю разделение на пробелы и запятые, поэтому у меня также есть эта функция по умолчанию:
std::vector<string> TokenizeDefault( const string str )
{
using namespace std;
regex re( "[\\s,]+" );
return Tokenize( str, re );
}
"[\\s,]+"
проверяет пробелы (\\s
) и запятые (,
).
Обратите внимание, если вы хотите разделить wstring
вместо string
,
- измените все
std::regex
наstd::wregex
- измените все
sregex_token_iterator
наwsregex_token_iterator
Обратите внимание, вы можете также взять строковый аргумент по ссылке, в зависимости от вашего компилятора.
Если вы хотите использовать boost, но хотите использовать целую строку в качестве разделителя (вместо отдельных символов, как в большинстве ранее предложенных решений), вы можете использовать boost_split_iterator
Пример кода, включающий удобный шаблон:
#include <iostream>
#include <vector>
#include <boost/algorithm/string.hpp>
template<typename _OutputIterator>
inline void split(
const std::string& str,
const std::string& delim,
_OutputIterator result)
{
using namespace boost::algorithm;
typedef split_iterator<std::string::const_iterator> It;
for(It iter=make_split_iterator(str, first_finder(delim, is_equal()));
iter!=It();
++iter)
{
*(result++) = boost::copy_range<std::string>(*iter);
}
}
int main(int argc, char* argv[])
{
using namespace std;
vector<string> splitted;
split("HelloFOOworldFOO!", "FOO", back_inserter(splitted));
// or directly to console, for example
split("HelloFOOworldFOO!", "FOO", ostream_iterator<string>(cout, "\n"));
return 0;
}
Использование std::stringstream
, как у вас, прекрасно работает и делает именно то, что вы хотели. Если вы просто ищете другой способ сделать что-то, вы можете использовать std::find()
/ std::find_first_of()
и std::string::substr()
.
Вот пример:
#include <iostream>
#include <string>
int main()
{
std::string s("Somewhere down the road");
std::string::size_type prev_pos = 0, pos = 0;
while( (pos = s.find(' ', pos)) != std::string::npos )
{
std::string substring( s.substr(prev_pos, pos-prev_pos) );
std::cout << substring << '\n';
prev_pos = ++pos;
}
std::string substring( s.substr(prev_pos, pos-prev_pos) ); // Last word
std::cout << substring << '\n';
return 0;
}
Существует функция с именем strtok
#include<string>
using namespace std;
vector<string> split(char* str,const char* delim)
{
char* saveptr;
char* token = strtok_r(str,delim,&saveptr);
vector<string> result;
while(token != NULL)
{
result.push_back(token);
token = strtok_r(NULL,delim,&saveptr);
}
return result;
}
Вот решение для регулярных выражений, которое использует только стандартную библиотеку регулярных выражений. (Я немного заржавел, поэтому может быть несколько синтаксических ошибок, но это по крайней мере общая идея)
#include <regex.h>
#include <string.h>
#include <vector.h>
using namespace std;
vector<string> split(string s){
regex r ("\\w+"); //regex matches whole words, (greedy, so no fragment words)
regex_iterator<string::iterator> rit ( s.begin(), s.end(), r );
regex_iterator<string::iterator> rend; //iterators to iterate thru words
vector<string> result<regex_iterator>(rit, rend);
return result; //iterates through the matches to fill the vector
}
stringstream может быть удобен, если вам нужно проанализировать строку не пробелы:
string s = "Name:JAck; Spouse:Susan; ...";
string dummy, name, spouse;
istringstream iss(s);
getline(iss, dummy, ':');
getline(iss, name, ';');
getline(iss, dummy, ':');
getline(iss, spouse, ';')
До сих пор я использовал его в Boost , но мне нужно было что-то, что не не зависит от этого, поэтому я пришел к этому:
static void Split(std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true)
{
std::ostringstream word;
for (size_t n = 0; n < input.size(); ++n)
{
if (std::string::npos == separators.find(input[n]))
word << input[n];
else
{
if (!word.str().empty() || !remove_empty)
lst.push_back(word.str());
word.str("");
}
}
if (!word.str().empty() || !remove_empty)
lst.push_back(word.str());
}
Хорошо, что в separators
вы можете передать более одного символа.
Коротко и элегантно
#include <vector>
#include <string>
using namespace std;
vector<string> split(string data, string token)
{
vector<string> output;
size_t pos = string::npos; // size_t to avoid improbable overflow
do
{
pos = data.find(token);
output.push_back(data.substr(0, pos));
if (string::npos != pos)
data = data.substr(pos + token.size());
} while (string::npos != pos);
return output;
}
может использовать любую строку в качестве разделителя, также может использоваться с двоичными данными (std :: string поддерживает двоичные данные, включая нули)
с помощью:
auto a = split("this!!is!!!example!string", "!!");
выход:
this
is
!example!string
Я сделал это, потому что мне нужен был простой способ разделения строк и строк на основе c ... Надеюсь, кому-то еще это тоже пригодится. Кроме того, он не зависит от токенов, и вы можете использовать поля в качестве разделителей, что является еще одним ключом, который мне был нужен.
Я уверен, что есть улучшения, которые могут быть сделаны, чтобы еще больше улучшить его элегантность, и, пожалуйста, делайте это всеми средствами
StringSplitter.hpp:
#include <vector>
#include <iostream>
#include <string.h>
using namespace std;
class StringSplit
{
private:
void copy_fragment(char*, char*, char*);
void copy_fragment(char*, char*, char);
bool match_fragment(char*, char*, int);
int untilnextdelim(char*, char);
int untilnextdelim(char*, char*);
void assimilate(char*, char);
void assimilate(char*, char*);
bool string_contains(char*, char*);
long calc_string_size(char*);
void copy_string(char*, char*);
public:
vector<char*> split_cstr(char);
vector<char*> split_cstr(char*);
vector<string> split_string(char);
vector<string> split_string(char*);
char* String;
bool do_string;
bool keep_empty;
vector<char*> Container;
vector<string> ContainerS;
StringSplit(char * in)
{
String = in;
}
StringSplit(string in)
{
size_t len = calc_string_size((char*)in.c_str());
String = new char[len + 1];
memset(String, 0, len + 1);
copy_string(String, (char*)in.c_str());
do_string = true;
}
~StringSplit()
{
for (int i = 0; i < Container.size(); i++)
{
if (Container[i] != NULL)
{
delete[] Container[i];
}
}
if (do_string)
{
delete[] String;
}
}
};
StringSplitter.cpp:
#include <string.h>
#include <iostream>
#include <vector>
#include "StringSplit.hpp"
using namespace std;
void StringSplit::assimilate(char*src, char delim)
{
int until = untilnextdelim(src, delim);
if (until > 0)
{
char * temp = new char[until + 1];
memset(temp, 0, until + 1);
copy_fragment(temp, src, delim);
if (keep_empty || *temp != 0)
{
if (!do_string)
{
Container.push_back(temp);
}
else
{
string x = temp;
ContainerS.push_back(x);
}
}
else
{
delete[] temp;
}
}
}
void StringSplit::assimilate(char*src, char* delim)
{
int until = untilnextdelim(src, delim);
if (until > 0)
{
char * temp = new char[until + 1];
memset(temp, 0, until + 1);
copy_fragment(temp, src, delim);
if (keep_empty || *temp != 0)
{
if (!do_string)
{
Container.push_back(temp);
}
else
{
string x = temp;
ContainerS.push_back(x);
}
}
else
{
delete[] temp;
}
}
}
long StringSplit::calc_string_size(char* _in)
{
long i = 0;
while (*_in++)
{
i++;
}
return i;
}
bool StringSplit::string_contains(char* haystack, char* needle)
{
size_t len = calc_string_size(needle);
size_t lenh = calc_string_size(haystack);
while (lenh--)
{
if (match_fragment(haystack + lenh, needle, len))
{
return true;
}
}
return false;
}
bool StringSplit::match_fragment(char* _src, char* cmp, int len)
{
while (len--)
{
if (*(_src + len) != *(cmp + len))
{
return false;
}
}
return true;
}
int StringSplit::untilnextdelim(char* _in, char delim)
{
size_t len = calc_string_size(_in);
if (*_in == delim)
{
_in += 1;
return len - 1;
}
int c = 0;
while (*(_in + c) != delim && c < len)
{
c++;
}
return c;
}
int StringSplit::untilnextdelim(char* _in, char* delim)
{
int s = calc_string_size(delim);
int c = 1 + s;
if (!string_contains(_in, delim))
{
return calc_string_size(_in);
}
else if (match_fragment(_in, delim, s))
{
_in += s;
return calc_string_size(_in);
}
while (!match_fragment(_in + c, delim, s))
{
c++;
}
return c;
}
void StringSplit::copy_fragment(char* dest, char* src, char delim)
{
if (*src == delim)
{
src++;
}
int c = 0;
while (*(src + c) != delim && *(src + c))
{
*(dest + c) = *(src + c);
c++;
}
*(dest + c) = 0;
}
void StringSplit::copy_string(char* dest, char* src)
{
int i = 0;
while (*(src + i))
{
*(dest + i) = *(src + i);
i++;
}
}
void StringSplit::copy_fragment(char* dest, char* src, char* delim)
{
size_t len = calc_string_size(delim);
size_t lens = calc_string_size(src);
if (match_fragment(src, delim, len))
{
src += len;
lens -= len;
}
int c = 0;
while (!match_fragment(src + c, delim, len) && (c < lens))
{
*(dest + c) = *(src + c);
c++;
}
*(dest + c) = 0;
}
vector<char*> StringSplit::split_cstr(char Delimiter)
{
int i = 0;
while (*String)
{
if (*String != Delimiter && i == 0)
{
assimilate(String, Delimiter);
}
if (*String == Delimiter)
{
assimilate(String, Delimiter);
}
i++;
String++;
}
String -= i;
delete[] String;
return Container;
}
vector<string> StringSplit::split_string(char Delimiter)
{
do_string = true;
int i = 0;
while (*String)
{
if (*String != Delimiter && i == 0)
{
assimilate(String, Delimiter);
}
if (*String == Delimiter)
{
assimilate(String, Delimiter);
}
i++;
String++;
}
String -= i;
delete[] String;
return ContainerS;
}
vector<char*> StringSplit::split_cstr(char* Delimiter)
{
int i = 0;
size_t LenDelim = calc_string_size(Delimiter);
while(*String)
{
if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
{
assimilate(String, Delimiter);
}
if (match_fragment(String, Delimiter, LenDelim))
{
assimilate(String,Delimiter);
}
i++;
String++;
}
String -= i;
delete[] String;
return Container;
}
vector<string> StringSplit::split_string(char* Delimiter)
{
do_string = true;
int i = 0;
size_t LenDelim = calc_string_size(Delimiter);
while (*String)
{
if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
{
assimilate(String, Delimiter);
}
if (match_fragment(String, Delimiter, LenDelim))
{
assimilate(String, Delimiter);
}
i++;
String++;
}
String -= i;
delete[] String;
return ContainerS;
}
Примеры:
int main(int argc, char*argv[])
{
StringSplit ss = "This:CUT:is:CUT:an:CUT:example:CUT:cstring";
vector<char*> Split = ss.split_cstr(":CUT:");
for (int i = 0; i < Split.size(); i++)
{
cout << Split[i] << endl;
}
return 0;
}
Будет выводить:
Это
это
пример
CString
int main(int argc, char*argv[])
{
StringSplit ss = "This:is:an:example:cstring";
vector<char*> Split = ss.split_cstr(':');
for (int i = 0; i < Split.size(); i++)
{
cout << Split[i] << endl;
}
return 0;
}
int main(int argc, char*argv[])
{
string mystring = "This[SPLIT]is[SPLIT]an[SPLIT]example[SPLIT]string";
StringSplit ss = mystring;
vector<string> Split = ss.split_string("[SPLIT]");
for (int i = 0; i < Split.size(); i++)
{
cout << Split[i] << endl;
}
return 0;
}
int main(int argc, char*argv[])
{
string mystring = "This|is|an|example|string";
StringSplit ss = mystring;
vector<string> Split = ss.split_string('|');
for (int i = 0; i < Split.size(); i++)
{
cout << Split[i] << endl;
}
return 0;
}
Чтобы сохранить пустые записи (по умолчанию пустые поля будут исключены):
StringSplit ss = mystring;
ss.keep_empty = true;
vector<string> Split = ss.split_string(":DELIM:");
Цель состояла в том, чтобы сделать его похожим на метод Split () в C #, где разбиение строки так же просто, как:
String[] Split =
"Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None);
foreach(String X in Split)
{
Console.Write(X);
}
Я надеюсь, что кто-то еще может найти это столь же полезным, как и я.
Как насчет этого?
#include <string>
#include <vector>
using namespace std;
vector<string> split(string str, const char delim) {
vector<string> v;
string tmp;
for(string::const_iterator i; i = str.begin(); i <= str.end(); ++i) {
if(*i != delim && i != str.end()) {
tmp += *i;
} else {
v.push_back(tmp);
tmp = "";
}
}
return v;
}
Вот еще один способ сделать это ..
void split_string(string text,vector<string>& words)
{
int i=0;
char ch;
string word;
while(ch=text[i++])
{
if (isspace(ch))
{
if (!word.empty())
{
words.push_back(word);
}
word = "";
}
else
{
word += ch;
}
}
if (!word.empty())
{
words.push_back(word);
}
}
Мне нравится использовать методы boost /regex для этой задачи, поскольку они обеспечивают максимальную гибкость для определения критериев разделения.
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main() {
std::string line("A:::line::to:split");
const boost::regex re(":+"); // one or more colons
// -1 means find inverse matches aka split
boost::sregex_token_iterator tokens(line.begin(),line.end(),re,-1);
boost::sregex_token_iterator end;
for (; tokens != end; ++tokens)
std::cout << *tokens << std::endl;
}
Недавно мне пришлось разбить верблюжье слово на подслово. Здесь нет разделителей, только верхние символы.
#include <string>
#include <list>
#include <locale> // std::isupper
template<class String>
const std::list<String> split_camel_case_string(const String &s)
{
std::list<String> R;
String w;
for (String::const_iterator i = s.begin(); i < s.end(); ++i) { {
if (std::isupper(*i)) {
if (w.length()) {
R.push_back(w);
w.clear();
}
}
w += *i;
}
if (w.length())
R.push_back(w);
return R;
}
Например, это разбивает «AQueryTrades» на «A», «Query» и «Trades». Функция работает с узкими и широкими строками. Поскольку он уважает текущую локаль, он разбивает RaumfahrtÜberwachungsVerordnung на Raumfahrt, Überwachungs и Verordnung.
Примечание. std::upper
должно быть действительно передано как аргумент шаблона функции. Тогда более обобщенные из этой функции могут быть разделены на разделители, такие как ","
, ";"
или " "
тоже.
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;
vector<string> split(const string &s, char delim) {
vector<string> elems;
stringstream ss(s);
string item;
while (getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
int main() {
vector<string> x = split("thi is an sample test",' ');
unsigned int i;
for(i=0;i<x.size();i++)
cout<<i<<":"<<x[i]<<endl;
return 0;
}
Этот ответ берет строку и помещает ее в вектор строк. Он использует библиотеку наддува.
#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));
Загрузите Boost ! : -)
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace boost;
int main(int argc, char**argv) {
typedef vector < string > list_type;
list_type list;
string line;
line = "Somewhere down the road";
split(list, line, is_any_of(" "));
for(int i = 0; i < list.size(); i++)
{
cout << list[i] << endl;
}
return 0;
}
Этот пример дает вывод -
Somewhere
down
the
road