Как мне перебрать слова строки?

Я пытаюсь перебрать слова строки.

Можно предположить, что строка состоит из слов, разделенных пробелами.

Обратите внимание, что меня не интересуют строковые функции Си или подобные манипуляции /доступ к символам. Кроме того, в своем ответе просьба отдавать предпочтение элегантности, а не эффективности.

Лучшее решение, которое у меня есть сейчас:

#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);
}

Есть ли более элегантный способ сделать это?

2747 голосов | спросил 27 revs, 14 users 30%
Ashwin Nanjappa
1 Jam1000000amThu, 01 Jan 1970 03:00:00 +030070 1970, 03:00:00

29 ответов


0

Для чего стоит, вот еще один способ извлечь токены из входной строки, опираясь только на стандартные библиотечные средства. Это пример силы и элегантности дизайна 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>{}};
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Я использую это, чтобы разделить строку разделителем. Первый помещает результаты в предварительно построенный вектор, второй возвращает новый вектор.

 #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", ':');
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Возможное решение с использованием 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) с использованием всех видов разделителей.

Подробнее см. документацию .

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0
#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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
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 ... остальное необязательно. Он не использует потоки или библиотеку надстройки, но достаточно гибок, чтобы иметь возможность естественным образом принимать некоторые из этих внешних типов.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Вот еще одно решение. Он компактен и достаточно эффективен:

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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Это мой любимый способ перебора строки. Вы можете делать все, что вы хотите для каждого слова.

string line = "a line of text to iterate through";
string word;

istringstream iss(line, istringstream::in);

while( iss >> word )     
{
    // Do something on `word` here...
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Это похоже на вопрос о переполнении стека. токенизировать строку в 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;
    }
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Мне нравится следующее, потому что это помещает результаты в вектор, поддерживает строку в качестве разделителя и дает контроль над сохранением пустых значений. Но это выглядит не так хорошо.

#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() прекрасно работает.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

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-файлы.

Не продавайте по этой сделке «Элегантность над производительностью» .

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Вот функция разделения, которая:

  • является общим
  • использует стандарт 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";,");
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

У меня есть 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;

Тогда вместо печати вы можете поместить его в вектор.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Еще один гибкий и быстрый способ

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 );

Ограничено воображением;)

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Вот простое решение, которое использует только стандартную библиотеку регулярных выражений

#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

Обратите внимание, вы можете также взять строковый аргумент по ссылке, в зависимости от вашего компилятора.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Если вы хотите использовать 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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Вот решение для регулярных выражений, которое использует только стандартную библиотеку регулярных выражений. (Я немного заржавел, поэтому может быть несколько синтаксических ошибок, но это по крайней мере общая идея)

#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
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

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, ';')
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

До сих пор я использовал его в 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 вы можете передать более одного символа.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Коротко и элегантно

#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
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Я сделал это, потому что мне нужен был простой способ разделения строк и строк на основе 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);
}

Я надеюсь, что кто-то еще может найти это столь же полезным, как и я.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Как насчет этого?

#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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Вот еще один способ сделать это ..

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);
  }
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Мне нравится использовать методы 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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Недавно мне пришлось разбить верблюжье слово на подслово. Здесь нет разделителей, только верхние символы.

#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 должно быть действительно передано как аргумент шаблона функции. Тогда более обобщенные из этой функции могут быть разделены на разделители, такие как ",", ";" или " " тоже.

ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0
#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;
}
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Этот ответ берет строку и помещает ее в вектор строк. Он использует библиотеку наддува.

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18
0

Загрузите 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
ответил André 11 PMpTue, 11 Apr 2017 23:25:18 +030025Tuesday 2017, 23:25:18

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132