【问题标题】:C++: How do I split a string into evenly-sized smaller strings?C ++:如何将字符串拆分为大小均匀的较小字符串?
【发布时间】:2023-04-02 02:39:01
【问题描述】:

在 C++ 中,如何将字符串拆分成大小均匀的较小字符串?

例如,我有一个字符串“012345678”,并希望将其拆分为 5 个较小的字符串,这应该返回“01”、“23”、“45”、“67”、“8”之类的内容.

我无法确定较小字符串的长度。在前面的示例中,原始字符串的大小为 9,我想将其拆分为 5 个较小的字符串,因此除最后一个之外的每个较小字符串的长度应为 9 / 5 = 1,但最后一个的长度为 9 - 1* 4 = 5,这是不可接受的。

所以这个问题的正式定义:原字符串被分割成正好n个子字符串,并且没有两个子字符串的长度相差大于1。

我的重点不是 C++ 语法或库。这是如何设计一种算法,使返回的字符串大小几乎相等。

【问题讨论】:

  • 您能否提供一个关于字符串的示例以及您希望较小的字符串看起来像什么?
  • 你指的是std::string还是一般的char*(c-string)?
  • @muntoo 不是同一个问题。
  • @Shuo 是的,这就是我说“另见”的原因。

标签: c++ string algorithm


【解决方案1】:

divide N items into M parts,长度在一个单位以内,可以用公式(N*i+N)/M - (N*i)/M作为i'th部分的长度,如下图。

 #include <string>
 #include <iostream>
 using namespace std;

 int main() {
   string text = "abcdefghijklmnopqrstuvwxyz";
   int N = text.length();
   for (int M=3; M<14; ++M) {
     cout <<" length:"<< N <<"  parts:"<< M << "\n";
     int at, pre=0, i;
     for (pre = i = 0; i < M; ++i) {
       at = (N+N*i)/M;
       cout << "part " << i << "\t" << pre << "\t" << at;
       cout << "\t" << text.substr(pre, at-pre) << "\n";
       pre = at;
     }
   }
   return 0;
 } 

例如,当M 为 4 或 5 时,上面的代码会产生:

  length:26  parts:4
 part 0 0   6   abcdef
 part 1 6   13  ghijklm
 part 2 13  19  nopqrs
 part 3 19  26  tuvwxyz
  length:26  parts:5
 part 0 0   5   abcde
 part 1 5   10  fghij
 part 2 10  15  klmno
 part 3 15  20  pqrst
 part 4 20  26  uvwxyz

【讨论】:

    【解决方案2】:

    我的解决方案:

    std::vector<std::string> split(std::string const & s, size_t count)
    {
           size_t minsize = s.size()/count;
           int extra = s.size() - minsize * count;
           std::vector<std::string> tokens;
           for(size_t i = 0, offset=0 ; i < count ; ++i, --extra)
           {
              size_t size = minsize + (extra>0?1:0);
              if ( (offset + size) < s.size())
                   tokens.push_back(s.substr(offset,size));
              else
                   tokens.push_back(s.substr(offset, s.size() - offset));
              offset += size;
           }       
           return tokens;
    }
    

    测试代码:

    int main() 
    {
          std::string s;
          while (std::cin >> s)
          {
            std::vector<std::string> tokens = split(s, 5);
            //output
            std::copy(tokens.begin(), tokens.end(), 
                  std::ostream_iterator<std::string>(std::cout, ", "));
            std::cout << std::endl;
          }
    }
    

    输入:

    012345
    0123456
    01234567
    012345678
    0123456789
    01234567890
    

    输出:

    01, 2, 3, 4, 5, 
    01, 23, 4, 5, 6, 
    01, 23, 45, 6, 7, 
    01, 23, 45, 67, 8, 
    01, 23, 45, 67, 89, 
    012, 34, 56, 78, 90, 
    

    在线演示:http://ideone.com/gINtK

    此解决方案倾向于使标记均匀,即所有标记的大小可能不同。

    【讨论】:

    • 我不认为这是正确的。因为 size = 1,你最终得到 0, 1, 2, 3, 4, 5, 6...
    • @Shuo:是的。我对此表示怀疑。现在更正了。
    • 把“012345”分成5个子串怎么样?
    • @Shuo:你想怎么拆分?你的问题不够清楚。
    • 是的,我想我没有明确提出我的问题,现在我有了正式的定义。
    【解决方案3】:

    知道子串的长度就足够了;
    假设 m 是您的字符串的size()

    int k = (m%n == 0)? n : n-m%n;  
    

    那么k 的子串长度应该是m/nn-k 的长度是m/n+1

    【讨论】:

      【解决方案4】:

      你会得到你想要分割它的迭代器,然后用它们来构造新的字符串。例如:

      std::string s1 = "string to split";
      std::string::iterator halfway = s1.begin() + s1.size() / 2;
      std::string s2(s1.begin(), halfway);
      std::string s3(halfway, s1.end());
      

      【讨论】:

        【解决方案5】:

        假设字符串长度为L,它必须拆分为n 子字符串。

        # Find the next multiple of `n` greater than or equal to `L`
        
        L = 9
        n = 5
        
        LL = n * (L / n)
        if LL < L:
            LL += n
        
        # Split a string of length LL into n equal sizes. The string is at
        # most (n-1) longer than L.
        
        lengths = [(LL / n) for x in range (n)]
        
        # Remove one from the first (or any) (LL-L) elements.
        for i in range (LL-L):
            lengths [i] = lengths [i] - 1
        
        # Get indices from lengths. 
        s = 0
        idx = []
        for i in lengths:
            idx.append (s)
            s = s + i
        idx.append (L)
        
        print idx
        

        编辑: 好吧好吧,我忘了应该是C++。

        编辑: 就这样吧……

        #include <vector>
        #include <iostream>
        
        unsigned int L = 13;
        unsigned int n = 5;
        
        int
        main ()
        {
          int i;
          unsigned int LL;
          std::vector<int> lengths, idx;
        
          /* Find the next multiple of `n` greater than or equal to `L` */
          LL = n * (L / n);
          if (LL < L)
            LL += n;
        
          /* Split a string of length LL into n equal sizes. The string is at
             most (n-1) longer than L. */
          for (i = 0; i < n; ++i)
            lengths.push_back (LL/n);
        
          /*  Remove one from the first (or any) (LL-L) elements. */
          for (i = 0; i < LL - L; ++i)
            --lengths [i];
        
          /* Get indices from lengths.  */
          int s = 0;
          for (auto &ii: lengths)
            {
              idx.push_back (s);
              s += ii;
            }
        
          idx.push_back (L);
        
          for (auto &i : idx)
            std::cout << i << " ";
        
          std::cout << std::endl;
          return 0;
        }
        

        【讨论】:

          【解决方案6】:

          试试substr

          【讨论】:

            猜你喜欢
            • 2014-02-16
            • 2021-06-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多