【问题标题】:How can I split a string by a delimiter into an array?如何通过分隔符将字符串拆分为数组?
【发布时间】:2009-05-20 20:48:22
【问题描述】:

我是编程新手。我一直在尝试用 C++ 编写一个函数,将字符串的内容分解为给定参数的字符串数组,例如:

string str = "___this_ is__ th_e str__ing we__ will use__";

应该返回字符串数组:

cout << stringArray[0]; // 'this'
cout << stringArray[1]; // ' is'
cout << stringArray[2]; // ' th'
cout << stringArray[3]; // 'e str'
cout << stringArray[4]; // 'ing we'
cout << stringArray[5]; // ' will use'

我可以很好地标记字符串,但对我来说最困难的部分是如何在为其分配当前字符串之前指定 stringArray 中的元素数量以及如何从函数返回 stringArray。

有人能告诉我如何编写函数吗?

Edit1:我不一定需要将结果放在字符串数组中,只要我可以将其作为具有某种索引的常规变量调用的任何容器即可。

【问题讨论】:

  • 家庭作业,也许?没关系,当然,但我来自不同人群的家庭作业问题的答案......
  • @Iothar 的答案似乎更有效。

标签: c++ function string


【解决方案1】:

这是我第一次尝试使用向量和字符串:

vector<string> explode(const string& str, const char& ch) {
    string next;
    vector<string> result;

    // For each character in the string
    for (string::const_iterator it = str.begin(); it != str.end(); it++) {
        // If we've hit the terminal character
        if (*it == ch) {
            // If we have some characters accumulated
            if (!next.empty()) {
                // Add them to the result vector
                result.push_back(next);
                next.clear();
            }
        } else {
            // Accumulate the next character into the sequence
            next += *it;
        }
    }
    if (!next.empty())
         result.push_back(next);
    return result;
}

希望这能让您对如何进行此操作有所了解。在您的示例字符串中,它使用此测试代码返回正确的结果:

int main (int, char const **) {
    std::string blah = "___this_ is__ th_e str__ing we__ will use__";
    std::vector<std::string> result = explode(blah, '_');

    for (size_t i = 0; i < result.size(); i++) {
        cout << "\"" << result[i] << "\"" << endl;
    }
    return 0;
}

【讨论】:

  • explode() 的第一个参数应该是一个常量引用。然后编译器会报错,所以 'it' 需要是一个 string::const_iterator。
  • @Magnus:谢谢,添加了修复:)
  • 您应该检查next 是否不为空,如果是,请将其附加到循环后的结果中。否则,explode char 之后的最后一个元素将不会被包含。
  • 最后一个元素被忽略!我在下面提出了一个解决方案,它有效!
  • @Veseliq 我编辑了评论并添加了 if 语句 - 一旦我的编辑获得批准,它就会显示出来。
【解决方案2】:

使用 STL(抱歉没有未测试的编译器)

#include <vector>
#include <string>
#include <sstream>

int main()
{
    std::vector<std::string>   result;

    std::string str = "___this_ is__ th_e str__ing we__ will use__";

    std::stringstream  data(str);

    std::string line;
    while(std::getline(data,line,'_'))
    {
        result.push_back(line); // Note: You may get a couple of blank lines
                                // When multiple underscores are beside each other.
    }
}

// 或定义一个令牌

#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <sstream>

struct Token: public std::string  // Yes I know this is nasty.
{                                 // But it is just to demosntrate the principle.    
};

std::istream& operator>>(std::istream& s,Token& t)
{
    std::getline(s,t,'_');
   
    // *** 
    // Remove extra '_' characters from the stream.
    char c;
    while(s && ((c = s.get()) != '_')) {/*Do Nothing*/}
    if (s)
    {
        s.unget(); // Put back the last char as it is not '_'
    }
    return s;
}

int main()
{   

    std::string str = "___this_ is__ th_e str__ing we__ will use__";

    std::stringstream  data(str);

    std::vector<std::string>   result(std::istream_iterator<Token>(data),
                                      std::istream_iterator<Token>());
}

【讨论】:

  • 因此在 while 循环中添加检查以跳过空“行”。
  • 这是用户的练习。
【解决方案3】:

它对我有用:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

vector<string> explode( const string &delimiter, const string &explodeme);

int main(int argc, char *argv[])
{
    string str = "I have a lovely bunch of cocoa nuts";
    cout<<str<<endl;
    vector<string> v = explode(" ", str);
    for(int i=0; i<v.size(); i++)
        cout <<i << " ["<< v[i] <<"] " <<endl;
}

vector<string> explode( const string &delimiter, const string &str)
{
    vector<string> arr;

    int strleng = str.length();
    int delleng = delimiter.length();
    if (delleng==0)
        return arr;//no change

    int i=0;
    int k=0;
    while( i<strleng )
    {
        int j=0;
        while (i+j<strleng && j<delleng && str[i+j]==delimiter[j])
            j++;
        if (j==delleng)//found delimiter
        {
            arr.push_back(  str.substr(k, i-k) );
            i+=delleng;
            k=i;
        }
        else
        {
            i++;
        }
    }
    arr.push_back(  str.substr(k, i-k) );
    return arr;
}

来源: http://www.zedwood.com/article/106/cpp-explode-function

【讨论】:

    【解决方案4】:

    您可以使用字符串向量(std::vector&lt;std::string&gt;),使用 push_back 将每个标记附加到它,然后从您的标记化函数中返回它。

    【讨论】:

      【解决方案5】:

      使用 std::vector 作为动态数组并将其作为结果返回。

      【讨论】:

        【解决方案6】:

        也许您应该使用列表而不是数组。这样你就不需要提前知道元素的数量。您也可以考虑使用 STL 容器。

        【讨论】:

          【解决方案7】:

          如果您坚持将 stringArray 设为与 std::vector&lt;&gt; 相对的数组(这是正确的做法),您必须:

          1. 进行两次传球(你看,一次数)
          2. 自己实现一个动态数组。

          使用向量更容易vector::push_back() 将新内容附加到末尾。所以:

          vector* explode(string s){
            vector<string> *v = new vector<string>
            //...
            // in a loop
              v->push_back(string_fragment);
            //...
            return v;
          }
          

          毕竟不需要为了完整起见。

          要返回您使用char ** 的字符串数组。

          char ** explode(const char *in){
            ...
          
          }
          

          顺便说一句——调用函数如何知道返回数组中有多少元素?你也必须解决这个问题。使用std::vector&lt;&gt; 除非您受到外力的约束...

          【讨论】:

          • v->push_back(string_fragment);
          • 我认为将堆栈分配的向量传回,或获取对要填充的向量的引用是更好的选择,然后在函数中分配原始向量,然后将删除职责传递给客户端。
          • @GMan:也许你是对的。我还在翻译中说 c++,并且有很多 c 的习惯徘徊...
          【解决方案8】:

          等到你的数据结构类,然后用链表编码。不过,如果是为了家庭作业,您可能只需初始化非常大的数组即​​可。

          【讨论】:

            【解决方案9】:

            以下代码:

            template <typename OutputIterator>
            int explode(const string &s, const char c, OutputIterator output) {
                stringstream  data(s);
                string line;
                int i=0;
                while(std::getline(data,line,c)) { *output++ = line; i++; }
                return i;
            }
            
            int main(...) {
              string test="H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0";
              cout << test << endl; 
              vector<string> event;
            **This is the main call**
              int evts = explode(test,':', back_inserter(event));
              for (int k=0; k<evts; k++) 
                cout << event[k] << "~";
              cout << endl;
            }
            

            输出

            H:AMBV4:2:182.45:182.45:182.45:182.45:182.41:32:17700:3229365:201008121711:0
            H~AMBV4~2~182.45~182.45~182.45~182.45~182.41~32~17700~3229365~201008121711~0~
            

            【讨论】:

              【解决方案10】:

              这是我编写的代码(完整)。可能对有相同需求的人有用。

              #include <string>
              #include <iostream>
              #include <sstream>
              #include <vector>
              using namespace std;
              
              int main(){
                      std::string s = "scott:tiger:mushroom";
                      std::string delimiter = ":";
              
                      std::vector<std::string> outputArr;
                      size_t pos = 0;
                      std::string token;
                      while ((pos = s.find(delimiter)) != std::string::npos) {
                          token = s.substr(0, pos);
                          s.erase(0, pos + delimiter.length());
                          outputArr.push_back(token);
                      }
                      outputArr.push_back(s);
              
                      // Printing Array to see the results
                      std::cout<<"====================================================================================\n";
                      for ( int i=0;i<outputArr.size();i++){
                              std::cout<<outputArr[i]<<"\n";
                      }
                      std::cout<<"====================================================================================\n";
              }
              

              干杯!!

              【讨论】:

                【解决方案11】:

                我认为我已经写了一个更简单的解决方案。

                std::vector<std::string> explode(const std::string& string, const char delimiter) {
                
                std::vector<std::string> result;
                unsigned int start = 0, pos = 0;
                
                while (pos != string.length()) {
                    if (string.at(pos) == delimiter || pos + 1 == string.length()) {
                        unsigned int size = (pos - start) + ((pos + 1) == string.length() ? 1 : 0);
                        if (size != 0) { // Make this 'if' as a option? like a parameter with removeEmptyString?
                            result.push_back(string.substr(start, size));
                        }
                        start = pos + 1;
                    }
                    pos++;
                }
                
                return std::move(result);
                

                }

                【讨论】:

                  【解决方案12】:

                  这对我有用:

                  #include <iostream>
                  #include <vector>
                  #include <string>
                  #include <sstream>  
                  
                  using namespace std;
                  
                  vector<string> split(string str, char delimiter) {
                    vector<string> internal;
                    stringstream ss(str); // Turn the string into a stream.
                    string tok;
                  
                    while(getline(ss, tok, delimiter)) {
                      internal.push_back(tok);
                    }
                  
                    return internal;
                  }
                  
                  int main(int argc, char **argv) {
                    string myCSV = "one,two,three,four";
                    vector<string> sep = split(myCSV, ',');
                  
                    // If using C++11 (which I recommend)
                    /* for(string t : sep)
                     *  cout << t << endl;
                     */
                  
                    for(int i = 0; i < sep.size(); ++i)
                      cout << sep[i] << endl;
                  }
                  

                  来源:http://code.runnable.com/VHb0hWMZp-ws1gAr/splitting-a-string-into-a-vector-for-c%2B%2B

                  【讨论】:

                    【解决方案13】:
                    # turn a string into a deque based on a delimiter string
                    bool tolist(deque<string>& list,string basis,const string& cutter) {
                        bool found = false;
                        if (!cutter.empty()) {
                            while (!basis.empty() ) {
                                string::size_type pos = basis.find(cutter);
                                if (pos != string::npos) {
                                    found = true;
                                    list.push_back(basis.substr(0, pos)); //pos says 2
                                    basis = basis.substr(pos+cutter.size(),string::npos);
                                } else {
                                    list.push_back(basis);
                                    basis.clear();
                                }
                            }
                        }
                        return found;
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-03-03
                      • 2014-03-02
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-11-29
                      • 1970-01-01
                      相关资源
                      最近更新 更多