首页 文章

如何迭代字符串的单词?

提问于
浏览
2721

我正在尝试迭代字符串的单词 .

可以假设该字符串由用空格分隔的单词组成 .

请注意,我对C字符串函数或那种字符操作/访问不感兴趣 . 另外,请在答案中优先考虑优雅而不是效率 .

我现在最好的解决方案是:

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

有没有更优雅的方式来做到这一点?

30 回答

  • 16

    短而优雅

    #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
    
  • 11

    使用 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;
    }
    
  • 34

    我喜欢使用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;
    }
    
  • 17

    使用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) .

    有关详细信息,请参阅documentation .

  • 174
    #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;
    }
    
  • 8

    如果需要使用非空格符号解析字符串,则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, ';')
    
  • 9

    这个答案接受字符串并将其放入字符串向量中 . 它使用boost库 .

    #include <boost/algorithm/string.hpp>
    std::vector<std::string> strs;
    boost::split(strs, "string to split", boost::is_any_of("\t "));
    
  • 13

    我喜欢以下内容,因为它将结果放入向量中,支持字符串作为delim并控制保持空值 . 但是,它看起来并不那么好 .

    #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(),其工作原理与此类似 . 并且,如果通过'white-space',你真的意味着任何类型的空白区域,使用Boost与 is_any_of() 的分割效果很好 .

  • 29

    下面的代码使用 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;
    }
    
  • 50

    那这个呢:

    #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;
    }
    
  • 111

    这是另一种做法..

    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);
      }
    }
    
  • 23

    又一种灵活而快速的方式

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

    受想象力限制;)

  • 65

    如果您想使用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;
    }
    
  • 78

    这是一个仅使用标准正则表达式库的正则表达式解决方案 . (我有点生疏,所以可能会有一些语法错误,但这至少是一般的想法)

    #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
    }
    
  • 2337

    对于那些不能很好地牺牲代码大小的所有效率并将“高效”视为一种优雅的人来说,下面的内容应该是一个最佳点(我认为模板容器类是一个非常优雅的添加 . ):

    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<> 比不需要直接访问时更快 list<> ,你甚至可以创建自己的字符串类并使用类似 std::list<subString> 的地方 subString 不做任何副本以获得惊人的速度提升 .

    它比本页面上最快的标记化速度快一倍以上,几乎是其他标记的5倍 . 此外,使用完美的参数类型,您可以消除所有字符串和列表副本,以提高速度 .

    此外,它不会(非常低效)返回结果,而是将标记作为参考传递,因此如果您愿意,还可以使用多个调用来构建标记 .

    最后,它允许您指定是否通过最后一个可选参数从结果中修剪空标记 .

    它所需要的只是 std::string ......其余的都是可选的 . 它不使用流或boost库,但足够灵活,能够自然地接受这些外来类型中的一些 .

  • 808

    对于它的 Value ,这是从输入字符串中提取标记的另一种方法,仅依赖于标准库设施 . 这是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>{}};
    
  • 1228

    这是我最喜欢的迭代字符串的方法 . 你可以随心所欲地做任何事 .

    string line = "a line of text to iterate through";
    string word;
    
    istringstream iss(line, istringstream::in);
    
    while( iss >> word )     
    {
        // Do something on `word` here...
    }
    
  • 34

    这是另一种解决方案 . 它结构紧凑,效率高:

    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;
    }
    
  • 18

    STL没有这样的方法 .

    但是,您可以使用std::string::c_str()成员使用C的strtok()函数,也可以编写自己的函数 . 以下是我在快速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.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html

    如果您对代码示例有疑问,请发表评论,我会解释 .

    并且因为它没有实现 typedef 调用迭代器或重载 << 运算符并不意味着它是错误的代码 . 我经常使用C函数 . 例如,printfscanf都比std::cinstd::cout(显着)快,fopen语法对二进制类型更友好,并且它们也倾向于生成更小的EXE .

    不要在这个 "Elegance over performance" 交易中被卖掉 .

  • 13

    这是一个只使用标准正则表达式库的简单解决方案

    #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

    注意,您可能还希望通过引用获取字符串参数,具体取决于您的编译器 .

  • 14

    我有一个解决这个问题的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;
    

    然后,您可以将其放在矢量中,而不是打印 .

  • 9

    我这样做是因为我需要一种简单的方法来分割字符串和基于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:");
    

    目标是使其类似于C#的Split()方法,其中拆分字符串就像:

    String[] Split = 
        "Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None);
    
    foreach(String X in Split)
    {
        Console.Write(X);
    }
    

    我希望其他人能像我一样认为这很有用 .

  • 334

    我使用strtok自己滚动并使用boost来分割字符串 . 我找到的最好的方法是C++ 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;
    }
    

    该工具包比这个简单的示例具有更多的灵活性,但它在将字符串解析为有用元素方面的实用性令人难以置信 .

  • 24

    最近我不得不将一个带有骆驼字的单词分成子字 . 没有分隔符,只有上面的字符 .

    #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”,“查询”和“交易” . 该函数适用于窄字符串和宽字符串 . 因为它尊重当前的地点,所以它将“RaumfahrtÜberwachungsVerordnung”分为“Raumfahrt”,“Überwachungs”和“Verordnung” .

    注意 std::upper 应该作为函数模板参数传递 . 然后,这个函数的更一般化也可以分割为 ","";"" " 等分隔符 .

  • 9

    我用它来分隔字符串 . 第一个将结果放在预先构造的向量中,第二个返回一个新向量 .

    #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", ':');
    
  • 10

    有一个名为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;
    }
    
  • 154

    到目前为止,我使用了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 中你可以传递多个角色 .

  • 9

    这是一个拆分函数:

    • 是通用的

    • 使用标准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";,");
    
  • 8

    这类似于Stack Overflow问题How do I tokenize a string in 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;
        }
    }
    
  • 39

    得到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
    

相关问题