代码之家  ›  专栏  ›  技术社区  ›  Ashish Patel

我怎么能只打印字母之间的逗号,而不是当它是一个独立的字母?[重复]

  •  0
  • Ashish Patel  · 技术社区  · 3 年前

    我知道如何在其他语言中做到这一点,但不知道如何在C++中做到这一点,我被迫在这里使用C++。

    我有一套弦( keywords )我要打印的 out 作为一个列表,字符串之间需要一个逗号,而不是后面的逗号。例如,在Java中,我会使用 StringBuilder 在我构建完字符串后,删除结尾的逗号。我如何用C++实现它?

    auto iter = keywords.begin();
    for (iter; iter != keywords.end( ); iter++ )
    {
        out << *iter << ", ";
    }
    out << endl;
    

    我最初尝试插入以下块来执行此操作(将逗号打印移到此处):

    if (iter++ != keywords.end())
        out << ", ";
    iter--;
    
    0 回复  |  直到 4 年前
        1
  •  2
  •   Sasha O    5 年前

    在即将到来的C++17编译器实验中,您可以使用 std::experimental::ostream_joiner :

    #include <algorithm>
    #include <experimental/iterator>
    #include <iostream>
    #include <iterator>
    
    int main()
    {
        int i[] = {1, 2, 3, 4, 5};
        std::copy(std::begin(i),
                  std::end(i),
                  std::experimental::make_ostream_joiner(std::cout, ", "));
    }
    

    使用 GCC 6.0 SVN Clang 3.9 SVN

        2
  •  2
  •   πάντα ῥεῖ    4 年前

    假设输出流大致正常,因此向其写入空字符串实际上没有任何作用:

    const char *padding = "";
    for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
        out << padding << *iter;
        padding = ", "
    }
    
        3
  •  1
  •   leanid.chaika    3 年前

    因为每个人都决定使用while循环,所以我将举一个for循环的例子。

    for (iter = keywords.begin(); iter != keywords.end(); iter++) {
      if (iter != keywords.begin()) cout << ", ";
      cout << *iter;
    }
    
        4
  •  0
  •   rahnema1    5 年前

    有很多聪明的解决方案,而且有太多的解决方案会在不让编译器完成其工作的情况下,对代码进行无望的破坏。

    这个 显而易见的解决方案是在特殊情况下进行第一次迭代:

    bool first = true;
    for (auto const& e: sequence) {
       if (first) { first = false; } else { out << ", "; }
       out << e;
    }
    

    这是一个非常简单的模式:

    1. 不会破坏循环:很明显,每个元素都会被迭代。
    2. 允许不只是放置分隔符,或实际打印列表,作为 else 块和循环体可以包含任意语句。

    它可能不是绝对最高效的代码,但一个预测良好的分支的潜在性能损失很可能会被这个庞大的分支所掩盖 std::ostream::operator<< .

        5
  •  0
  •   apokaliptis    5 年前

    使用中缀迭代器:

    // infix_iterator.h 
    // 
    // Lifted from Jerry Coffin's 's prefix_ostream_iterator 
    #if !defined(INFIX_ITERATOR_H_) 
    #define  INFIX_ITERATOR_H_ 
    #include <ostream> 
    #include <iterator> 
    template <class T, 
              class charT=char, 
              class traits=std::char_traits<charT> > 
    class infix_ostream_iterator : 
        public std::iterator<std::output_iterator_tag,void,void,void,void> 
    { 
        std::basic_ostream<charT,traits> *os; 
        charT const* delimiter; 
        bool first_elem; 
    public: 
        typedef charT char_type; 
        typedef traits traits_type; 
        typedef std::basic_ostream<charT,traits> ostream_type; 
        infix_ostream_iterator(ostream_type& s) 
            : os(&s),delimiter(0), first_elem(true) 
        {} 
        infix_ostream_iterator(ostream_type& s, charT const *d) 
            : os(&s),delimiter(d), first_elem(true) 
        {} 
        infix_ostream_iterator<T,charT,traits>& operator=(T const &item) 
        { 
            // Here's the only real change from ostream_iterator: 
            // Normally, the '*os << item;' would come before the 'if'. 
            if (!first_elem && delimiter != 0) 
                *os << delimiter; 
            *os << item; 
            first_elem = false; 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator*() { 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator++() { 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator++(int) { 
            return *this; 
        } 
    };     
    #endif 
    

    用法如下:

    #include "infix_iterator.h"
    
    // ...
    std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
    
        6
  •  0
  •   bolov    4 年前

    我建议你在lambda的帮助下切换第一个角色。

    std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };                  
    
    for (auto &k : keywords)
        std::cout << f() << k;