有没有办法在 C 中实现 Python 的“分隔符”.join() 的模拟?

发布于 2024-11-09 08:24:41 字数 175 浏览 0 评论 0原文

我发现的只是 boost::algorithm::string::join。然而,仅使用 Boost 进行连接似乎有点矫枉过正。那么也许有一些经过时间考验的食谱?

更新
抱歉,问题标题不好。 我正在寻找用分隔符连接字符串的方法,而不仅仅是一一连接。

All I've found is boost::algorithm::string::join. However, it seems like overkill to use Boost only for join. So maybe there are some time-tested recipes?

UPDATE:
Sorry, the question caption were bad.
I'm looking for method to concatenate strings with separator, not just to concatenate one-by-one.

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

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

发布评论

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

评论(8

瀞厅☆埖开 2024-11-16 08:24:41

既然您正在寻找一个配方,请继续使用 Boost 中的配方。一旦你克服了所有的通用性,它就不会太复杂:

  1. 分配一个地方来存储结果。
  2. 将序列的第一个元素添加到结果中。
  3. 当有其他元素时,请将分隔符和下一个元素附加到结果中。
  4. 返回结果。

这是一个在两个迭代器上运行的版本(与在范围上运行的 Boost 版本相反。

template <typename Iter>
std::string join(Iter begin, Iter end, std::string const& separator)
{
  std::ostringstream result;
  if (begin != end)
    result << *begin++;
  while (begin != end)
    result << separator << *begin++;
  return result.str();
}

Since you're looking for a recipe, go ahead and use the one from Boost. Once you get past all the genericity, it's not too complicated:

  1. Allocate a place to store the result.
  2. Add the first element of the sequence to the result.
  3. While there are additional elements, append the separator and the next element to the result.
  4. Return the result.

Here's a version that works on two iterators (as opposed to the Boost version, which operates on a range.

template <typename Iter>
std::string join(Iter begin, Iter end, std::string const& separator)
{
  std::ostringstream result;
  if (begin != end)
    result << *begin++;
  while (begin != end)
    result << separator << *begin++;
  return result.str();
}
情感失落者 2024-11-16 08:24:41

如果您确实想要 ''.join(),您可以将 std::copystd::ostream_iterator 一起使用到 std::stringstream

#include <algorithm> // for std::copy
#include <iterator>  // for std::ostream_iterator
#include <sstream>   // for std::stringstream

std::vector<int> values(); // initialize these
std::stringstream buffer;
std::copy(values.begin(), values.end(), std::ostream_iterator<int>(buffer));

这会将所有值插入到缓冲区中。您还可以为 std::ostream_iterator 指定自定义分隔符,但这将附加在末尾(这是与 join 的显着区别)。如果您不需要分隔符,这将满足您的需求。

If you really want ''.join(), you can use std::copy with an std::ostream_iterator to a std::stringstream.

#include <algorithm> // for std::copy
#include <iterator>  // for std::ostream_iterator
#include <sstream>   // for std::stringstream

std::vector<int> values(); // initialize these
std::stringstream buffer;
std::copy(values.begin(), values.end(), std::ostream_iterator<int>(buffer));

This will insert all the values to buffer. You can also specify a custom separator for std::ostream_iterator but this will get appended at the end (this is the significant difference to join). If you don't want a separator, this will do just what you want.

人事已非 2024-11-16 08:24:41

简单来说,容器中的类型是 int:

std::string s = std::accumulate(++v.begin(), v.end(), std::to_string(v[0]),
                     [](const std::string& a, int b){
                           return a + ", " + std::to_string(b);
                     });

simply, where the type in the container is an int:

std::string s = std::accumulate(++v.begin(), v.end(), std::to_string(v[0]),
                     [](const std::string& a, int b){
                           return a + ", " + std::to_string(b);
                     });
最佳男配角 2024-11-16 08:24:41

这适用于 C++17:

template<class...T>
std::string join(const std::string& sep, T&&...strings) {
    if constexpr(sizeof...(T)) {
        auto t = ((strings + sep) + ...);
        return t.substr(0, t.size() - sep.size());    
    } else {
        return "";
    }
}

int main() {
    std::cout << join(",", "apple", "orange", "banana") << std::endl;
    std::cout << join(",") << std::endl;
}

它应该打印:

apple,orange,banana

This works with C++17:

template<class...T>
std::string join(const std::string& sep, T&&...strings) {
    if constexpr(sizeof...(T)) {
        auto t = ((strings + sep) + ...);
        return t.substr(0, t.size() - sep.size());    
    } else {
        return "";
    }
}

int main() {
    std::cout << join(",", "apple", "orange", "banana") << std::endl;
    std::cout << join(",") << std::endl;
}

It should print:

apple,orange,banana
等待圉鍢 2024-11-16 08:24:41

C++ 字符串的实现非常高效。

std::string s = s1 + s2 + s3;

这可能会更快:

std::string str;
str.reserve(total_size_to_concat);

for (std::size_t i = 0; i < s.length(); i++)
{
  str.append(s[i], s[i].length());
}

但这基本上就是编译器使用 operator+ 所做的事情,并且进行了最低限度的优化,除了猜测要保留的大小之外。
别害羞。看一下 字符串的实现。 :)

C++ strings are implemented efficiently.

std::string s = s1 + s2 + s3;

This could be faster:

std::string str;
str.reserve(total_size_to_concat);

for (std::size_t i = 0; i < s.length(); i++)
{
  str.append(s[i], s[i].length());
}

But this is basically what your compiler do with operator+ and a minimum of optimization except it is guessing the size to reserve.
Don't be shy. Take a look at the implementation of strings. :)

神经暖 2024-11-16 08:24:41

这是我发现更方便使用的另一个版本:

std::string join(std::initializer_list<std::string> initList, const std::string& separator = "\\")
{
    std::string s;
    for(const auto& i : initList)
    {
        if(s.empty())
        {
            s = i;
        }
        else
        {
            s += separator + i;
        }
    }

    return s;
}

然后您可以这样调用它:

join({"C:", "Program Files", "..."});

Here is another version that I find more handy to use:

std::string join(std::initializer_list<std::string> initList, const std::string& separator = "\\")
{
    std::string s;
    for(const auto& i : initList)
    {
        if(s.empty())
        {
            s = i;
        }
        else
        {
            s += separator + i;
        }
    }

    return s;
}

You can then call it this way:

join({"C:", "Program Files", "..."});
绝對不後悔。 2024-11-16 08:24:41

如果您在项目中使用Qt,则可以直接使用QString的join函数(QString 参考)并且它按照 python 的预期工作。一些示例:

QStringList strList;
qDebug() << strList.join(" and ");

结果:""

strList << "id = 1";
qDebug() << strList.join(" and ");

结果:"id = 1"

strList << "name = me";
qDebug() << strList.join(" and ");

结果:"id = 1 and name = me"

If you use Qt in your project you can directly use the join function of QString (QString Reference) and it works as expected from python. Some examples:

QStringList strList;
qDebug() << strList.join(" and ");

Result: ""

strList << "id = 1";
qDebug() << strList.join(" and ");

Result: "id = 1"

strList << "name = me";
qDebug() << strList.join(" and ");

Result: "id = 1 and name = me"

海未深 2024-11-16 08:24:41

这是另一个简单的解决方案:

template<class T>
std::string str_join(const std::string& delim, const T& items)
{
    std::string s;

    for (const auto& item : items) {
        if (!s.empty()) {
            s += delim;
        }
        s += item;
    }

    return s;
}

对于那些不喜欢 begin()end() 作为参数并且更喜欢整个容器的人。对于那些不喜欢字符串流而更喜欢一些 operator std::string() const 的人来说。

用法:

auto s1 = str_join(", ", std::vector<const char*>{"1","2","3"});

struct X
{
    operator std::string() const
    {
        return "X";
    }
};

auto s2 = str_join(":", std::vector<X>{{}, {}, {}});

应该与 C++11 及更高版本一起使用。

Just another simple solution:

template<class T>
std::string str_join(const std::string& delim, const T& items)
{
    std::string s;

    for (const auto& item : items) {
        if (!s.empty()) {
            s += delim;
        }
        s += item;
    }

    return s;
}

For those who don't like begin(), end() as arguments and prefer just the whole container. And for those who don't like string streams and prefer some operator std::string() const instead.

Usage:

auto s1 = str_join(", ", std::vector<const char*>{"1","2","3"});

struct X
{
    operator std::string() const
    {
        return "X";
    }
};

auto s2 = str_join(":", std::vector<X>{{}, {}, {}});

Should work with C++11 and later.

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