做逗号分隔字符串时,如何处理最后一个逗号?(复制)

时间:2020-12-14 12:49:05

Possible Duplicates:
Don't print space after last number
Printing lists with commas C++

可能的重复:不要打印空格后的最后一个数字打印列表与逗号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;
}

This prints out: 1,2,3,4,5, However I want: 1,2,3,4,5

这个输出是1 2 3 4 5,不管我想要1 2 3 4 5

How can I achieve that in an elegant way?

我怎样才能以优雅的方式做到这一点呢?

I see there is some confusion about what I mean with "elegant": E.g. no slowing down "if-clause" in my loop. Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone through the loop.

我知道我的意思是“优雅”的意思有些混淆:例如,在我的循环中没有慢下来的“if-从句”。想象在向量中有100.000个元素!如果这就是您所要提供的,我宁愿在遍历循环之后删除最后一个逗号。

10 个解决方案

#1


28  

How about this:

这个怎么样:

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

No need to add extra variables and doesn't even depend on boost! Actually, in addition to the "no additional variable in the loop" requirement, one could say that there is not even a loop :)

不需要添加额外的变量,甚至不依赖boost!实际上,除了“循环中没有附加变量”的要求之外,还可以说甚至没有循环:)

#2


14  

Detecting the one before last is always tricky, detecting the first is very easy.

检测前一个总是很棘手,检测第一个是很容易的。

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

#3


10  

Using Karma from Boost Spirit - has a reputation for being fast.

利用来自提升精神的业力-有快速的名声。

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

#4


8  

Try:

试一试:

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

Alternatively, if the "if" is making you worried:

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

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

#5


5  

Personally, I like a solution that does not cause potential memory allocations (because the string grows larger than needed). An extra-if within the loop body should be tractable thanks to branch target buffering, but I would do so:

就我个人而言,我喜欢一种不会导致潜在内存分配的解决方案(因为字符串的增长大于需要)。由于分支目标缓冲,在循环体内部的额外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;
    }
}

Alternatively, BYORA (bring your own re-usable algorithm):

或者,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, ", ");
}

so that

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

output:

输出:

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

The neat thing is it works for every output stream, any container that has forward iterators, with any infix, and with any infix type (interesting e.g. when you use wide strings).

最妙的是,它适用于每一个输出流、任何具有前向迭代器的容器、任何中缀和任何中缀类型(有趣的是,当您使用宽字符串时)。

#6


3  

I like moving the test outside the loop.
It only needs to be done once. So do it first.

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

Like this:

是这样的:

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

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

#7


1  

You can either trim the string at the end, or using single for loop instead of foreach and dont concatenate at the last iteration

您可以在末尾修改字符串,或者使用单个for循环代替foreach,在最后一次迭代中不连接

#8


1  

Well, if you format into a stringstream anyway, you can just trim the resulting string by one character:

好吧,如果你格式化成一个stringstream,你只需要将结果字符串修剪一个字符:

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

If the string is empty, than the second argument says -1, which means everything and does not crash and if the string is non-empty, it always ends with a comma.

如果字符串是空的,第二个参数是-1,这意味着所有内容都不会崩溃,如果字符串不是空的,它总是以逗号结束。

But if you write to an output stream directly, I never found anything better than the first flag.

但是如果您直接向输出流写入,我发现没有比第一个标志更好的东西了。

That is unless you want to use join from boost.string algo.

除非您想使用boost中的join。字符串算法。

#9


0  

This would work

这将工作

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

I suspect with "elegant" you mean "without introducing a new variable". But I think I would just do it "non-elegant" if I couldn't find anything else. It's still clear

我怀疑“优雅”你的意思是“不引入一个新的变量”。但是我觉得如果我找不到别的东西,我就会“不优雅”地去做。它仍然是清晰的

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

Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone thorough the loop.

想象在向量中有100.000个元素!如果这就是您所要提供的全部内容,我宁愿在深入循环之后删除最后一个逗号。

You are saying that as if printing ss << i is one machine instruction. Come on, executing that expression will execute lots of if's and loops inside. Your if will be nothing compared to that.

您是说,好像打印ss < i是一个机器指令。执行这个表达式会在里面执行很多if和循环。你的if和那相比什么都不是。

#10


-2  

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

< span lang = en - us > < o: p > < / o: p > < / span > < / p >

You can add the "\b" backspace

您可以添加“\b”备份空间

This will overwrite the extra "," .

这将覆盖额外的“,”。

for Example :

例如:

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

So the output would be

输出是

H

#1


28  

How about this:

这个怎么样:

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

No need to add extra variables and doesn't even depend on boost! Actually, in addition to the "no additional variable in the loop" requirement, one could say that there is not even a loop :)

不需要添加额外的变量,甚至不依赖boost!实际上,除了“循环中没有附加变量”的要求之外,还可以说甚至没有循环:)

#2


14  

Detecting the one before last is always tricky, detecting the first is very easy.

检测前一个总是很棘手,检测第一个是很容易的。

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

#3


10  

Using Karma from Boost Spirit - has a reputation for being fast.

利用来自提升精神的业力-有快速的名声。

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

#4


8  

Try:

试一试:

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

Alternatively, if the "if" is making you worried:

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

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

#5


5  

Personally, I like a solution that does not cause potential memory allocations (because the string grows larger than needed). An extra-if within the loop body should be tractable thanks to branch target buffering, but I would do so:

就我个人而言,我喜欢一种不会导致潜在内存分配的解决方案(因为字符串的增长大于需要)。由于分支目标缓冲,在循环体内部的额外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;
    }
}

Alternatively, BYORA (bring your own re-usable algorithm):

或者,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, ", ");
}

so that

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

output:

输出:

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

The neat thing is it works for every output stream, any container that has forward iterators, with any infix, and with any infix type (interesting e.g. when you use wide strings).

最妙的是,它适用于每一个输出流、任何具有前向迭代器的容器、任何中缀和任何中缀类型(有趣的是,当您使用宽字符串时)。

#6


3  

I like moving the test outside the loop.
It only needs to be done once. So do it first.

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

Like this:

是这样的:

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

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

#7


1  

You can either trim the string at the end, or using single for loop instead of foreach and dont concatenate at the last iteration

您可以在末尾修改字符串,或者使用单个for循环代替foreach,在最后一次迭代中不连接

#8


1  

Well, if you format into a stringstream anyway, you can just trim the resulting string by one character:

好吧,如果你格式化成一个stringstream,你只需要将结果字符串修剪一个字符:

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

If the string is empty, than the second argument says -1, which means everything and does not crash and if the string is non-empty, it always ends with a comma.

如果字符串是空的,第二个参数是-1,这意味着所有内容都不会崩溃,如果字符串不是空的,它总是以逗号结束。

But if you write to an output stream directly, I never found anything better than the first flag.

但是如果您直接向输出流写入,我发现没有比第一个标志更好的东西了。

That is unless you want to use join from boost.string algo.

除非您想使用boost中的join。字符串算法。

#9


0  

This would work

这将工作

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

I suspect with "elegant" you mean "without introducing a new variable". But I think I would just do it "non-elegant" if I couldn't find anything else. It's still clear

我怀疑“优雅”你的意思是“不引入一个新的变量”。但是我觉得如果我找不到别的东西,我就会“不优雅”地去做。它仍然是清晰的

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

Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone thorough the loop.

想象在向量中有100.000个元素!如果这就是您所要提供的全部内容,我宁愿在深入循环之后删除最后一个逗号。

You are saying that as if printing ss << i is one machine instruction. Come on, executing that expression will execute lots of if's and loops inside. Your if will be nothing compared to that.

您是说,好像打印ss < i是一个机器指令。执行这个表达式会在里面执行很多if和循环。你的if和那相比什么都不是。

#10


-2  

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

< span lang = en - us > < o: p > < / o: p > < / span > < / p >

You can add the "\b" backspace

您可以添加“\b”备份空间

This will overwrite the extra "," .

这将覆盖额外的“,”。

for Example :

例如:

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

So the output would be

输出是

H