如何处理最后一个逗号,当用逗号分隔字符串时?

时间:2011-07-14 12:07:34

标签: c++ string boost stringstream csv

  

可能重复:
  Don't print space after last number
  Printing lists with commas C++

#include <vector>
#include <iostream>
#include <sstream>
#include <boost/foreach.hpp>
using namespace std;

int main()
{
   vector<int> VecInts;

   VecInts.push_back(1);
   VecInts.push_back(2);
   VecInts.push_back(3);
   VecInts.push_back(4);
   VecInts.push_back(5);

   stringstream ss;
   BOOST_FOREACH(int i, VecInts)
   {
      ss << i << ",";
   }

   cout << ss.str();

   return 0;
}

打印出来:1,2,3,4,5, 但是我想:1,2,3,4,5

如何以优雅的方式实现这一目标?

我看到我对“优雅”的含义有些困惑:例如我的循环中没有减慢“if-clause”的速度。想象一下向量中的100.000个条目!如果这就是你要提供的全部内容,我宁愿在完成循环后删除最后一个逗号。

10 个答案:

答案 0 :(得分:31)

这个怎么样:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>

int main()
{
   std::vector<int> v;

   v.push_back(1);
   v.push_back(2);
   v.push_back(3);
   v.push_back(4);
   v.push_back(5);

   std::ostringstream ss;

   std::copy(v.begin(), v.end() - 1, std::ostream_iterator<int>(ss, ", "));
   ss << v.back();

   std::cout << ss.str() << "\n";
}

无需添加额外的变量,甚至不依赖于提升!实际上,除了“循环中没有额外的变量”要求之外,人们可以说甚至没有循环:)

答案 1 :(得分:14)

在最后检测之前总是很棘手,检测第一个很容易。

bool first = true;
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
  if (!first) { ss << ","; }
  first = false;
  ss << i;
}

答案 2 :(得分:10)

使用来自提升精神的业力 - 以快速而闻名。

#include <iostream>
#include <vector>
#include <boost/spirit/include/karma.hpp>

int main()
{
  std::vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  using namespace boost::spirit::karma;
  std::cout << format(int_ % ',', v) << std::endl;
}

答案 3 :(得分:8)

尝试:

if (ss.tellp ())
{
   ss << ",";
}
ss << i;

或者,如果“if”让你担心:

char *comma = "";
BOOST_FOREACH(int i, VecInts)
{
   ss << comma << i;
   comma = ",";
}

答案 4 :(得分:5)

就个人而言,我喜欢不会导致潜在内存分配的解决方案(因为字符串变得比需要的大)。由于分支目标缓冲,循环体内的额外if应该是易处理的,但我会这样做:

#include <vector>
#include <iostream>

int main () {
    using std::cout;
    typedef std::vector<int>::iterator iterator;

    std::vector<int> ints;    
    ints.push_back(5);
    ints.push_back(1);
    ints.push_back(4);
    ints.push_back(2);
    ints.push_back(3);


    if (!ints.empty()) {
        iterator        it = ints.begin();
        const iterator end = ints.end();

        cout << *it;
        for (++it; it!=end; ++it) {
            cout << ", " << *it;
        }
        cout << std::endl;
    }
}

或者,BYORA(带上你自己的可重复使用的算法):

// Follow the signature of std::getline. Allows us to stay completely
// type agnostic.
template <typename Stream, typename Iter, typename Infix>
inline Stream& infix (Stream &os, Iter from, Iter to, Infix infix_) {
    if (from == to) return os;
    os << *from;
    for (++from; from!=to; ++from) {
        os << infix_ << *from;
    }
    return os;
}

template <typename Stream, typename Iter>
inline Stream& comma_seperated (Stream &os, Iter from, Iter to) {
    return infix (os, from, to, ", ");
}

这样

...
comma_seperated(cout, ints.begin(), ints.end()) << std::endl;

infix(cout, ints.begin(), ints.end(), "-") << std::endl;
infix(cout, ints.begin(), ints.end(), "> <") << std::endl;
...

输出:

5, 1, 4, 2, 3
5-1-4-2-3
5> <1> <4> <2> <3

整洁的东西是它适用于每个输出流,任何具有前向迭代器的容器,任何中缀,以及任何中缀类型(有趣的是,例如当你使用宽字符串时)。

答案 5 :(得分:3)

我喜欢在循环外移动测试 它只需要做一次。所以先做。

像这样:

if (!VecInts.empty())
{
    ss << VecInts[0]

    for(any loop = ++(VecInts.begin()); loop != VecInts.end(); ++loop)
    {
        ss << "," << *loop;
    }
}

答案 6 :(得分:1)

您可以在最后修剪字符串,或者使用单个for循环而不是foreach,并且在最后一次迭代时不连接

答案 7 :(得分:1)

好吧,如果你格式化为stringstream,你可以将结果字符串修剪一个字符:

cout << ss.str().substr(0, ss.str().size() - 1);

如果字符串为空,则第二个参数为-1,表示一切并且不会崩溃,如果字符串为非空,则它总是以逗号结尾。

但是如果直接写入输出流,我找不到比first标志更好的东西。

除非您想使用boost.string algo中的join

答案 8 :(得分:0)

这样可行

stringstream ss;
BOOST_FOREACH(int const& i, VecInts)
{
   if(&i != &VecInts[0])
     ss << ", ";
   ss << i;
}

我怀疑“优雅”是指“不引入新变量”。但是,如果我找不到其他任何东西,我想我会把它做成“非优雅”。它仍然很清楚

stringstream ss;
bool comma = false;
BOOST_FOREACH(int i, VecInts)
{
   if(comma)
     ss << ", ";
   ss << i;
   comma = true;
}
  

想象一下向量中的100.000个条目!如果这就是你所要提供的全部内容,我宁愿在完成循环后删除最后一个逗号。

您说好像打印ss << i是一台机器指令。来吧,执行该表达式将执行许多if并在其中循环。你的if与此相比毫无意义。

答案 9 :(得分:-2)

cout << ss.str()<<"\b" <<" ";

您可以添加“\ b”退格

这将覆盖额外的“,”。

例如:

int main()
{
    cout<<"Hi";
    cout<<'\b';  //Cursor moves 1 position backwards
    cout<<" ";   //Overwrites letter 'i' with space
}

所以输出将是

H