【问题标题】:Split and convert from string to char array拆分并从字符串转换为字符数组
【发布时间】:2021-02-14 14:13:12
【问题描述】:

如何转换:

 string x = "1+2+3";

到:

 char y[] = {'1', '2', '3'};

我应该怎么做?

【问题讨论】:

  • 既然你除了一位数字,简单的for循环就足够了。到目前为止,您的尝试遇到了哪些问题?
  • 在字符串上使用 std::getline,并传递 '+' 作为分隔符

标签: c++ string char c++17


【解决方案1】:

任务是拆分一个用'+'分隔的字符串。在下面的示例中,使用了分隔符“,”。

将字符串拆分为标记是一项非常古老的任务。有许多可用的解决方案。都有不同的属性。有些难以理解,有些难以开发,有些更复杂、更慢或更快或更灵活或不灵活。

替代品

  1. 手工制作,多种变体,使用指针或迭代器,可能难以开发且容易出错。
  2. 使用旧式std::strtok 函数。也许不安全。也许不应该再使用了
  3. std::getline。最常用的实现。但实际上是一种“误用”,并不那么灵活
  4. 使用专门为此目的开发的专用现代功能,最灵活且最适合 STL 环境和算法环境。但速度较慢。

请在一段代码中查看 4 个示例。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>

using Container = std::vector<std::string>;
std::regex delimiter{ "," };


int main() {

    // Some function to print the contents of an STL container
    auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
        std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };

    // Example 1:   Handcrafted -------------------------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Search for comma, then take the part and add to the result
        for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {

            // So, if there is a comma or the end of the string
            if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {

                // Copy substring
                c.push_back(stringToSplit.substr(startpos, i - startpos));
                startpos = i + 1;
            }
        }
        print(c);
    }

    // Example 2:   Using very old strtok function ----------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
        for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
            c.push_back(token);
        }

        print(c);
    }

    // Example 3:   Very often used std::getline with additional istringstream ------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Put string in an std::istringstream
        std::istringstream iss{ stringToSplit };

        // Extract string parts in simple for loop
        for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
            ;

        print(c);
    }

    // Example 4:   Most flexible iterator solution  ------------------------------------------------

    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };


        Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
        //
        // Everything done already with range constructor. No additional code needed.
        //

        print(c);


        // Works also with other containers in the same way
        std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});

        print(c2);

        // And works with algorithms
        std::deque<std::string> c3{};
        std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));

        print(c3);
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    您可以使用std::vector&lt;std::string&gt; 而不是char[],这样,它可以处理多于一位的数字。试试这个:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <sstream>
    
    int main() {
        using namespace std;
        std::string str("1+2+3");
        std::string buff;
        std::stringstream ss(str);
        
        std::vector<std::string> result;
        while(getline(ss, buff, '+')){
            result.push_back(buff);
        }
        
        for(std::string num : result){
            std::cout << num << std::endl;
        }
    }
    

    这是一个coliru link,表明它适用于多于一位的数字。

    【讨论】:

      【解决方案3】:

      这是我的步骤:

      • 将原来的string转换成char*
      • 使用strtok函数将得到的char*与分隔符+分开。我将每个令牌存储到 vector&lt;char&gt;
      • 将此vector&lt;char&gt; 转换为C 字符数组char*
      #include <iostream>
      #include <string.h>
      #include <vector>
      using namespace std;
      
      int main()
      {
          string line = "1+2+3";
          std::vector<char> vectChar;
          // convert the original string into a char array to allow splitting
          char* input= (char*) malloc(sizeof(char)*line.size());
          strcpy(input,line.data());
          // splitting the string 
          char *token = strtok(input, "+");
      
          int len=0;
          while(token) {
              std::cout << *token;
              vectChar.push_back(*token);
              token = strtok(NULL, "+");
          }
          // end of splitting step
      
          std::cout << std::endl;
          //test display the content of the vect<char>={'1', '2', ...}
          for (int i=0; i< vectChar.size(); i++)
          {
              std::cout << vectChar[i];
          }
          // Now that the vector contains the needed list of char
          // we need to convert it to char array (char*)
          // first malloc
          char* buffer = (char*) malloc(vectChar.size()*sizeof(char));
          // then convert the vector into char*
          std::copy(vectChar.begin(), vectChar.end(), buffer);
          std::cout << std::endl;
          //now buffer={'1', '2', ...}
          // les ut stest by displaying
          while ( *buffer != '\0')
          {
              printf("%c", *buffer);
              buffer++;
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        您可以在https://repl.it/@JomaCorpFX/StringSplit#main.cpp 中运行/检查此代码

        代码

        #include <iostream>
        #include <vector>
        
        std::vector<std::string> Split(const std::string &data, const std::string &toFind)
        {
            std::vector<std::string> v;
            if (data.empty() || toFind.empty())
            {
                v.push_back(data);
                return v;
            }
            size_t ini = 0;
            size_t pos;
            while ((pos = data.find(toFind, ini)) != std::string::npos)
            {
                std::string s = data.substr(ini, pos - ini);
                if (!s.empty())
                {
                    v.push_back(s);
                }
                ini = pos + toFind.length();
            }
            if (ini < data.length())
            {
                v.push_back(data.substr(ini));
            }
        
            return v;
        }
        
        int main()
        {
            std::string x = "1+2+3";
            for (auto value : Split(x, u8"+"))
            {
                std::cout << "Value: " << value << std::endl;
            }
            std::cout << u8"Press enter to continue... ";
            std::cin.get();
            return EXIT_SUCCESS;
        }
        

        输出

        Value: 1
        Value: 2
        Value: 3
        Press enter to continue...
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-01
          • 2018-04-18
          相关资源
          最近更新 更多