Как мне перебрать слова строки?
Я пытаюсь перебрать слова строки.
Можно предположить, что строка состоит из слов, разделенных пробелами.
Обратите внимание, что меня не интересуют строковые функции Си или подобные манипуляции/доступ к символам. Кроме того, пожалуйста, дайте приоритет элегантности над эффективностью в вашем ответе.
Лучшее решение, которое у меня есть сейчас:
#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);
}
Есть ли более элегантный способ сделать это?
Ответы
Ответ 1
Для чего это стоит, вот еще один способ извлечь токены из входной строки, опираясь только на стандартные средства библиотеки. Это пример силы и элегантности дизайна 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>{}};
Ответ 2
Я использую это, чтобы разделить строку разделителем. Первый помещает результаты в предварительно построенный вектор, второй возвращает новый вектор.
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
template <typename Out>
void split(const std::string &s, char delim, Out result) {
std::istringstream iss(s);
std::string item;
while (std::getline(iss, 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", ':');
Ответ 3
Возможное решение с использованием 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) с использованием всех видов разделителей.
Подробнее см. .
Ответ 4
#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;
}
Ответ 5
Для тех, с кем он не подходит, чтобы пожертвовать всей эффективностью для размера кода и увидеть "эффективный" как тип элегантности, следующее должно поразить сладкое место (и я думаю, что класс контейнера-шаблона - это удивительно элегантное дополнение.):
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<>
, когда прямой доступ не нужен, и вы даже можете создать свой собственный string class и используйте что-то вроде std::list<subString>
, где subString
не делает копии для невероятной скорости.
Это более чем вдвое быстрее, чем самый быстрый токенизировать на этой странице и почти в 5 раз быстрее, чем некоторые другие. Также с идеальными типами параметров вы можете исключить все копии строк и списков для дополнительного увеличения скорости.
Кроме того, он не выполняет (крайне неэффективный) возврат результата, а скорее передает токены в качестве ссылки, что также позволяет вам создавать токены, используя несколько вызовов, если вы этого пожелаете.
Наконец, он позволяет указать, нужно ли обрезать пустые токены из результатов с помощью последнего необязательного параметра.
Все, что ему нужно, это std::string
... остальные необязательны. Он не использует потоки или библиотеку boost, но достаточно гибкий, чтобы естественным образом принимать некоторые из этих иностранных типов.
Ответ 6
Здесь другое решение. Он компактен и достаточно эффективен:
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;
}
Ответ 7
Это мой любимый способ перебора строки. Вы можете делать все, что хотите, за каждое слово.
string line = "a line of text to iterate through";
string word;
istringstream iss(line, istringstream::in);
while( iss >> word )
{
// Do something on `word` here...
}
Ответ 8
Это похоже на Stack вопрос с переполнением Как я хочу tokenize строку в С++?.
#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;
}
}
Ответ 9
Мне нравится следующее, потому что он помещает результаты в вектор, поддерживает строку как разделитель и дает контроль над сохранением пустых значений. Но это не выглядит так хорошо.
#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 имеет split()
, который работает частично так. И, если по "белому пространству" вы действительно имеете в виду любой тип белого пространства, использование разделения Boost с is_any_of()
отлично работает.
Ответ 10
STL уже не имеет такого метода.
Однако вы можете использовать функцию C strtok()
, используя std::string::c_str()
, или вы можете написать свой собственный. Вот пример кода, который я нашел после быстрого поиска Google ("Разделение строки STL"):
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.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
Если у вас есть вопросы о образце кода, оставьте комментарий, и я объясню.
И только потому, что он не реализует typedef
называемый итератором или перегрузкой, оператор <<
не означает, что это плохой код. Я использую C-функции довольно часто. Например, printf
и scanf
работают быстрее, чем std::cin
и std::cout
(значительно), синтаксис fopen
намного более дружелюбен для двоичных типов, и они также имеют тенденцию создавать меньшие EXE.
Не продавайте эту сделку "Elegance over performance".
Ответ 11
Вот функция разделения, которая:
- является общим
- использует стандартный С++ (без повышения)
- принимает несколько разделителей
-
игнорирует пустые токены (их можно легко изменить)
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 left of the string
return v;
}
Пример использования:
vector<string> v = split<string>("Hello, there; World", ";,");
vector<wstring> v = split<wstring>(L"Hello, there; World", L";,");
Ответ 12
Еще один гибкий и быстрый способ
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;
}
}
Использовать его с вектором строк (Edit: Поскольку кто-то указал, что не наследует классы 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 );
Ограничено воображением;)
Ответ 13
У меня есть 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;
Затем вместо печати вы можете поместить его в вектор.
Ответ 14
Здесь простое решение, в котором используется только стандартная библиотека регулярных выражений
#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
Обратите внимание, что вы также можете взять строковый аргумент по ссылке, в зависимости от вашего компилятора.
Ответ 15
Использование 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;
}
Ответ 16
Если вам нравится использовать 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;
}
Ответ 17
Существует функция с именем 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;
}
Ответ 18
Вот решение регулярного выражения, которое использует только стандартную библиотеку регулярных выражений. (Я немного ржавый, поэтому могут быть несколько синтаксических ошибок, но это, по крайней мере, общая идея)
#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
}
Ответ 19
Строковый поток может быть удобным, если вам нужно проанализировать строку с помощью непространственных символов:
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, ';')
Ответ 20
До сих пор я использовал тот, что был в 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
вы можете передать более одного символа.
Ответ 21
Я перекатил свой собственный, используя strtok, и использовал boost для разделения строки. Лучший метод, который я нашел, это С++ String Toolkit Library. Это невероятно гибко и быстро.
#include <iostream>
#include <vector>
#include <string>
#include <strtk.hpp>
const char *whitespace = " \t\r\n\f";
const char *whitespace_and_punctuation = " \t\r\n\f;,=";
int main()
{
{ // normal parsing of a string into a vector of strings
std::string s("Somewhere down the road");
std::vector<std::string> result;
if( strtk::parse( s, whitespace, result ) )
{
for(size_t i = 0; i < result.size(); ++i )
std::cout << result[i] << std::endl;
}
}
{ // parsing a string into a vector of floats with other separators
// besides spaces
std::string s("3.0, 3.14; 4.0");
std::vector<float> values;
if( strtk::parse( s, whitespace_and_punctuation, values ) )
{
for(size_t i = 0; i < values.size(); ++i )
std::cout << values[i] << std::endl;
}
}
{ // parsing a string into specific variables
std::string s("angle = 45; radius = 9.9");
std::string w1, w2;
float v1, v2;
if( strtk::parse( s, whitespace_and_punctuation, w1, v1, w2, v2) )
{
std::cout << "word " << w1 << ", value " << v1 << std::endl;
std::cout << "word " << w2 << ", value " << v2 << std::endl;
}
}
return 0;
}
Инструментарий обладает гораздо большей гибкостью, чем показывает этот простой пример, но его полезность при разборе строки в полезных элементах невероятна.
Ответ 22
Короткие и элегантные
#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
Ответ 23
Я сделал это, потому что мне был нужен простой способ разделить строки и строки на основе 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(), где разделение строки так же просто, как:
String[] Split =
"Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None);
foreach(String X in Split)
{
Console.Write(X);
}
Я надеюсь, что кто-то еще найдет это полезным, как я.
Ответ 24
Как насчет этого:
#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;
}
Ответ 25
Вот еще один способ сделать это.
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);
}
}
Ответ 26
Мне нравится использовать методы 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;
}
Ответ 27
Недавно мне пришлось разбить слово с верблюжьим словом на подслов. Нет разделителей, только верхние символы.
#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
должно быть действительно передано как аргумент шаблона функции. Тогда более обобщенная из этой функции может разбиваться на разделители типа ","
, ";"
или " "
тоже.
Ответ 28
#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;
}
Ответ 29
Этот ответ берет строку и помещает ее в вектор строк. Он использует библиотеку boost.
#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));
Ответ 30
В приведенном ниже коде используется strtok()
, чтобы разбить строку на токены и сохранить токены в векторе.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
char one_line_string[] = "hello hi how are you nice weather we are having ok then bye";
char seps[] = " ,\t\n";
char *token;
int main()
{
vector<string> vec_String_Lines;
token = strtok( one_line_string, seps );
cout << "Extracting and storing data in a vector..\n\n\n";
while( token != NULL )
{
vec_String_Lines.push_back(token);
token = strtok( NULL, seps );
}
cout << "Displaying end result in vector line storage..\n\n";
for ( int i = 0; i < vec_String_Lines.size(); ++i)
cout << vec_String_Lines[i] << "\n";
cout << "\n\n\n";
return 0;
}