Есть ли более простой способ? - PullRequest
8 голосов
/ 09 августа 2011

Я хотел бы знать, есть ли более короткий / простой способ:

  1. Разделить входящую строку по словам
  2. Записать токены в обратном порядке в stdout

Есть два ограничения: без библиотек и без циклов

#include <string>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <deque>

void list_string_elements(std::string s) {
    using namespace std;

    istringstream iss (s);
    deque<string> v;

    copy(istream_iterator<string>(iss), istream_iterator<string>(), front_inserter(v));

    copy(v.begin(),v.end(),ostream_iterator<string>(cout,"\n"));
}

Ответы [ 3 ]

7 голосов
/ 09 августа 2011

Небольшое сокращение, мы можем избавиться от копии благодаря конструктору итератора deque:

void list_string_elements(std::string s) {
    using namespace std;

    istringstream iss (s);
    deque<string> v(istream_iterator<string>(iss), (istream_iterator<string>()));
    copy(v.rbegin(),v.rend(),ostream_iterator<string>(cout,"\n"));
}

Обратите внимание на дополнительные символы около istream_iterator<string>(), чтобы избежать самого неприятного анализа.

5 голосов
/ 09 августа 2011

Нет, потому что вам нужно хранить слова, пока не будет выбрано последнее.Сложнее попробовать токенизировать в обратном направлении.

Также нельзя использовать std::copy_backward, поскольку std::istream_iterator не является двунаправленным (только ввод).

std::deque идеально подходит для этой задачи.Вы могли бы также использовать vector + back_inserter и скопировать из v.rbegin() в v.rend() в ostream_iterator.

Кроме того, логика токенизации строки проще всего выражается с помощью istringstream.

По сути, это выглядит так, что нельзя добиться большего успеха.

Единственная религиозная мелочь - это то, что я не могу стоять using namespace, даже на уровне блока.

Мое предложение, с таким же количеством строк:

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

void output_tokens(const std::string& str)
{
    typedef std::istream_iterator<std::string> in_iterator;
    typedef std::ostream_iterator<std::string> out_iterator;

    std::istringstream in(str);
    std::vector<std::string> buffer(in_iterator(in), (in_iterator()));
    std::copy(buffer.rbegin(), buffer.rend(), out_iterator(std::cout, "\n"));
}

Важное редактирование: Вам нужна дополнительная пара скобок вокруг in_iterator(), чтобы избежать синтаксического анализа всего оператора в качестве объявления функции.@ У Стива Джессопа та же проблема.См. этот ошибочный пример , чтобы засвидетельствовать появление сообщения об ошибке, вызывающей растягивание волос, которое возникает в результате такой путаницы.

2 голосов
/ 09 августа 2011

Хорошо, что ваш учитель поощряет использование правильной функциональности C ++, но для забавы я бы сказал, что использование copy просто перемещает цикл вниз по стеку ... Я бы сказал, что рекурсия - это реальный способ делать это без использования явного цикла, что-то вроде ниже ...

#include <iostream>
#include <string>

typedef std::string::const_iterator iterator;

void print_reverse(iterator s, iterator i, iterator e)
{
  // last word
  if (i == e)
  {
    if (s != i)
      std::cout << std::string(s, i) << std::endl;
    return;
  }
  std::string word;
  if (*i == ' ')
  {
    // have word here
    word.assign(s, i);
    s = ++i;
  }
  else
    ++i;
  // recursively call   
  print_reverse(s, i, e);

  if (!word.empty())
    std::cout << word << std::endl;
}

int main(void)
{
  std::string foo ("foo bar bof bob");
  print_reverse(foo.begin(), foo.begin(), foo.end());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...