Можем ли мы разделить, манипулировать и воссоединить строку в c ++ одним оператором? - PullRequest
2 голосов
/ 20 сентября 2010

Это немного глупый вопрос, но из любопытства можно было бы разделить строку на запятую, выполнить функцию над строкой, а затем присоединить ее к запятой в одном выражении с C ++?

Это то, что я имею до сих пор:

string dostuff(const string& a) {
  return string("Foo");
}

int main() {
  string s("a,b,c,d,e,f");

  vector<string> foobar(100);
  transform(boost::make_token_iterator<string>(s.begin(), s.end(), boost::char_separator<char>(",")),
            boost::make_token_iterator<string>(s.end(), s.end(), boost::char_separator<char>(",")),
            foobar.begin(),
            boost::bind(&dostuff, _1));
  string result = boost::algorithm::join(foobar, ",");
}

Так что это приведет к превращению "a,b,c,d,e,f" в "Foo,Foo,Foo,Foo,Foo,Foo"

Я понимаю, что это OTT, но просто хотел расширить свое волшебство наддува.

Ответы [ 4 ]

1 голос
/ 20 сентября 2010

Я на самом деле работаю над библиотекой, чтобы позволить писать код более читабельным способом, чем одни итераторы ... не знаю, смогу ли я когда-нибудь закончить проект, хотя, кажется, мертвые проекты накапливаются на моем компьютере ... .

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

Итак, давайте предположим, что у нас есть подходящая библиотека:

struct DoStuff { std::string operator()(std::string const&); };

int main(int argc, char* argv[])
{
  std::string const reference = "a,b,c,d,e,f";

  std::string const result = boost::join(
    view::transform(
      view::split(reference, ","),
      DoStuff()
    ),
    ","
  );
}

Идея представления заключается в том, чтобы быть упаковщиком света в другой контейнер:

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

У меня уже работает transform часть, мне интересно, как split мог бы работать (в общем), но я думаю, что я займусь этим;)

1 голос
/ 20 сентября 2010
void dostuff(string& a) {
    a = "Foo";
}

int main()
{
    string s("a,b,c,d,e,f");
    vector<string> tmp;
    s = boost::join(
          (
            boost::for_each(
              boost::split(tmp, s, boost::is_any_of(",")),
              dostuff
            ),
            tmp
          ),
          ","
        );

    return 0;
}

К сожалению, я не могу исключить упоминание tmp дважды. Может быть, я подумаю кое о чем позже.

1 голос
/ 20 сентября 2010

Во-первых, обратите внимание, что ваша программа пишет «Foo, Foo, Foo, Foo, Foo, Foo ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "" к вашей строке результата - как уже упоминалось в комментариях, вы хотели использовать back_inserter там.

Что касается ответа, когда естьединственное значение, полученное из диапазона, я смотрю на std::accumulate (так как - это версия C ++ сворачивания / уменьшения)

#include <string>
#include <iostream>
#include <numeric>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/bind.hpp>
std::string dostuff(const std::string& a) {
  return std::string("Foo");
}
int main() {
  std::string s("a,b,c,d,e,f");
  std::string result =
    accumulate(
     ++boost::make_token_iterator<std::string>(s.begin(), s.end(), boost::char_separator<char>(",")),
       boost::make_token_iterator<std::string>(s.end(), s.end(), boost::char_separator<char>(",")),
       dostuff(*boost::make_token_iterator<std::string>(s.begin(), s.end(), boost::char_separator<char>(","))),
       boost::bind(std::plus<std::string>(), _1,
         bind(std::plus<std::string>(), ",",
            bind(dostuff, _2)))); // or lambda, for slightly better readability
  std::cout << result << '\n';
}

За исключением того, что теперь way поверх и повторяет make_token_iterator дважды.Я предполагаю, что boost.range выигрывает.

0 голосов
/ 20 сентября 2010

Хорошо, я думаю, что это возможно, но, пожалуйста, пожалуйста, не делайте этого на самом деле в рабочем коде.

Гораздо лучше было бы что-то вроде

std::string MakeCommaEdFoo(std::string input)
{
    std::size_t commas = std::count_if(input.begin(), input.end(),
        std::bind2nd(std::equal_to<char>(), ','));
    std::string output("foo");
    output.reserve((commas+1)*4-1);
    for(std::size_t idx = 1; idx < commas; ++idx)
        output.append(",foo");
    return output;
}

Мало того, что это будет работать лучше, следующему парню будет намного легче читать и понимать.

...