Reputation: 7775
This is a bit of a daft question, but out of curiousity would it be possibly to split a string on comma, perform a function on the string and then rejoin it on comma in one statement with C++?
This is what I have so far:
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, ",");
}
So this would result in turning "a,b,c,d,e,f"
into "Foo,Foo,Foo,Foo,Foo,Foo"
I realise this is OTT, but was just looking to expand my boost wizardry.
Upvotes: 2
Views: 910
Reputation: 299730
I am actually working on a library to allow writing code in a more readable fashion than iterators alone... don't know if I'll ever finish the project though, seems dead projects tend to accumulate on my computer...
Anyway the main reproach I have here is obviously the use of iterators. I tend to think of iterators as low-level implementation details, when coding you rarely want to use them at all.
So, let's assume that we have a proper library:
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()
),
","
);
}
The idea of a view is to be a lightwrapper around another container:
I already have the transform
part working, I am wondering how the split
could work (generally), but I think I'll get into it ;)
Upvotes: 1
Reputation: 72469
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;
}
Unfortunately I can't eliminate mentioning tmp
twice. Maybe I'll think of something later.
Upvotes: 1
Reputation: 47408
First, note that your program writes "Foo,Foo,Foo,Foo,Foo,Foo,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,," to your result string -- as already mentioned in comments, you wanted to use back_inserter there.
As for the answer, whenever there's a single value resulting from a range, I look at std::accumulate
(since that is the C++ version of fold/reduce)
#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';
}
Except now it's way over the top and repeats make_token_iterator twice. I guess boost.range wins.
Upvotes: 1
Reputation: 106530
Okay, I guess it's possible, but please please don't really do this in production code.
Much better would be something like
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;
}
Not only will it perform better, it will is much easier for the next guy to read and understand.
Upvotes: 0