Разбиение строки на вектор <string>слов - PullRequest
0 голосов
/ 08 декабря 2011

С Ускоренный C ++ (книга), я нашел этот код, идентичный программе, но обработанный в самой программе другой, и смутил меня в некоторой части.

Приведенный ниже код, ну, очевидно, он будет выводить каждое слово одно за другим (по циклам) на основе пользовательского ввода после того, как пользователь включил конец файла, а затем завершит программу.

int main()
{
    string s;
    while (cin >> s)
        cout << s << endl;
    return  0;
}

В отличие от приведенного выше кода, это слово будет хранить каждое слово в vector, затем использовать индексы i и j для обнаружения непробельного символа, и настоящий вопрос в том, что я не понимаю, как это происходит с вектором.

Что такое пробел в vector? Элемент?

Сначала я думал, что программа будет проходить через каждый символ , потому что я думал, что пробел - это символ (для которого предназначена функциональность i и j), затем , книга пришла и сказала, что она проходит через каждое слово , я не знаю, как проверить это сам, как я вижу, как внутренний процесс в самом компиляторе ..

vector<string> split(const string& s)
{
    vector<string> ret;
    typedef string::size_type string_size;
    string_size i = 0;

    // invariant: we have processed characters [original value of i, i) 
    while (i != s.size())
    {
        // ignore leading blanks
        // invariant: characters in range [original i, current i) are all spaces
     while (i != s.size() && isspace(s[i]))
         ++i;

     // find end of next word
     string_size j = i;
     // invariant: none of the characters in range [original j, current j)is a space
     while (j != s.size() && !isspace(s[j]))
         j++;
         // if we found some nonwhitespace characters 
         if (i != j) {
             // copy from s starting at i and taking j - i chars
             ret.push_back(s.substr(i, j - i));
             i = j;
         }
    }
    return ret;
}

int main() {
    string s;
    // read and split each line of input 
    while (getline(cin, s)) {
        vector<string> v = split(s);

        // write each word in v
        for (vector<string>::size_type i = 0; i != v.size(); ++i)
             cout << v[i] << endl;
    }
    return 0;
}

Ответы [ 2 ]

3 голосов
/ 08 декабря 2011

Код, который вы разместили выше, не разбивает строку текста на слова на основе пробела, вместо этого он разбивает строку на символы.Тем не менее, это если код действительно компилируется и не пропускает необходимые скобки ({, }). РЕДАКТИРОВАТЬ: На самом деле, если он разделяет слова или отдельные символы, зависит от того, куда идут фигурные скобки, суть в том, что код не компилируется.

Вот фиксированная версия кода, который разделяеткаждое слово вместо каждого символа простым перемещением последнего оператора if в split вне его непосредственного while блока:

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

vector<string> split(const string& s)
{
   vector<string> ret;
   typedef string::size_type string_size;
   string_size i = 0;

   // invariant: we have processed characters [original value of i, i) 
   while (i != s.size()) {
      // ignore leading blanks
      // invariant: characters in range [original i, current i) are all spaces
      while (i != s.size() && isspace(s[i]))
         ++i;

      // find end of next word
      string_size j = i;
      // invariant: none of the characters in range [original j, current j)is a space
      while (j != s.size() && !isspace(s[j]))
         j++;

      // if we found some nonwhitespace characters 
      if (i != j) {
         // copy from s starting at i and taking j - i chars
         ret.push_back(s.substr(i, j - i));
         i = j;
      }
   }
   return ret;
}

int main() {
   string s;
   // read and split each line of input 
   while (getline(cin, s)) {
      vector<string> v = split(s);

      // write each word in v
      for (vector<string>::size_type i = 0; i != v.size(); ++i)
      cout << v[i] << endl;
   }
   return 0;
}

То, что происходит с string, переданным split, таково:

  • Пока символы в строке (while (i != s.size()))
    • Пока мы читаем пробел изстрока while (i != s.size() && isspace(s[i]))
      • Увеличивайте счетчик до тех пор, пока мы не доберемся до начала слова (++i)
    • Установите конец слова в качестве начала словаслово (string_size j = i)
    • Пока мы все еще внутри этого слова и не до пробела (while (j != s.size() && !isspace(s[j])))
      • Увеличиваем счетчик, указывающий конец слова (j++)
    • Если есть несколько непробельных символов - конец больше, чем начало (if (i != j))
      • Создайте подстроку от начальной точки до конечной точки слова (s.substr(i, j - i)) и добавьте это слово к vector (ret.push_back(..)).
    • Прополощите и повторите.
1 голос
/ 08 декабря 2011

Если вы просто разбиваете по пространству, вам не нужно писать собственный метод. У STL есть варианты для вас.

        std::string line;
        std::vector<std::string> strings;
        while ( std::getline(std::cin, line))
        {
             std::istringstream s ( line);
             strings.insert(strings.end(), 
                 std::istream_iterator<std::string>(s),  
                 std::istream_iterator<std::string>());
        }

     //  For simplicity sake using lambda.   
        std::for_each(strings.begin(), strings.end(), [](const std::string& str)
        {
            std::cout << str << "\n";
        });
...