我们可以在 c++ 中拆分、操作和重新连接字符串吗?在一份声明中?

发布于 2024-09-24 04:30:15 字数 738 浏览 0 评论 0原文

这是一个有点愚蠢的问题,但出于好奇,是否有可能用 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,但只是想扩展我的加速魔法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

逆光飞翔i 2024-10-01 04:30:15

首先,请注意您的程序写入“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';
}

除了现在它远远超过顶部并重复 make_token_iterator 两次。我猜 boost.range 获胜。

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.

你爱我像她 2024-10-01 04:30:15
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。也许我稍后会想到一些事情。

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.

染柒℉ 2024-10-01 04:30:15

我实际上正在开发一个库,允许以比单独迭代器更可读的方式编写代码...不过不知道我是否会完成该项目,似乎死项目往往会在我的计算机上累积...

无论如何我在这里的主要责备显然是迭代器的使用。我倾向于将迭代器视为低级实现细节,在编码时您很少想使用它们。

因此,假设我们有一个合适的库:

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 是如何工作的(一般来说),但我想我会进入它;)

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:

  • from the user point of view it behaves like a container (minus the operations that actually modify the container structure)
  • from the implementation point of view, it's a lightweight object, containing as few data as possible --> the value is ephemeral here, and only lives as long as the iterator lives.

I already have the transform part working, I am wondering how the split could work (generally), but I think I'll get into it ;)

怕倦 2024-10-01 04:30:15

好吧,我想这是可能的,但是请不要在生产代码中这样做。

更好的是像这样的东西,

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;
}

它不仅性能更好,而且下一个人更容易阅读和理解。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文