C ++: Как разделить строку на строки меньшего размера одинакового размера? - PullRequest
7 голосов
/ 21 ноября 2011

Как в C ++ разделить строку на более мелкую строку равномерного размера?

Например, у меня есть строка "012345678", и я хочу, чтобы она разбила ее на 5 строк меньшего размера, и это должно вернутьмне что-то вроде «01», «23», «45», «67», «8».

У меня проблемы с определением длины меньших строк.В предыдущем примере исходная строка имеет размер 9, и я хочу разделить ее на 5 меньших строк, поэтому каждая строка меньшего размера, кроме последней, должна иметь длину 9/5 = 1, но тогда последняя будет иметь длину 9 -1 * 4 = 5, что недопустимо.

Таким образом, формальное определение этой проблемы : исходная строка разбита ТОЛЬКО на n подстрок, и никакие две подстроки не должны отличаться болеечем 1 в длину.

Я сфокусирован не на синтаксисе C ++ или библиотеке.Это как спроектировать алгоритм так, чтобы возвращаемая строка могла быть почти равной по размеру.

Ответы [ 6 ]

5 голосов
/ 21 ноября 2011

Чтобы разделить N элементов на M частей , с длинами в пределах одной единицы, вы можете использовать формулу (N*i+N)/M - (N*i)/M как длину i '-ой части, как показано ниже.

 #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
4 голосов
/ 21 ноября 2011

Мое решение:

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

Это решение стремится сделать токены четными , то есть все токены могут не иметь одинаковый размер.

1 голос
/ 21 ноября 2011

Достаточно знать длину подстрок;
Предположим, что m равно size() вашей строки:

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

Тогда k подстрок должно иметь длину m/n и n-k длины m/n+1.

0 голосов
/ 21 ноября 2011

Допустим, длина строки равна 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

EDIT: Хорошо, хорошо, я забыл, что это должен быть C ++.

EDIT: Вот и все ...

#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;
}
0 голосов
/ 21 ноября 2011

Вы получаете итераторы для того места, где вы хотите его разделить, а затем используете их для создания новых строк.Например:

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());
0 голосов
/ 21 ноября 2011

Попробуйте substr.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...