c++ - una - string_split
¿Cómo lidiar con la última coma, al hacer una cadena separada por comas? (10)
Bueno, si formatea un stringstream
todos modos, puede recortar la cadena resultante con un carácter:
cout << ss.str().substr(0, ss.str().size() - 1);
Si la cadena está vacía, entonces el segundo argumento dice -1, lo que significa todo y no se cuelga, y si la cadena no está vacía, siempre termina con una coma.
Pero si escribe directamente en una secuencia de salida, nunca encontré nada mejor que la first
bandera.
Eso es a menos que quieras usar join
de boost.string algo .
Posibles duplicados:
No imprima espacio después del último número
Impresión de listas con comas 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;
}
Esto imprime: 1,2,3,4,5,
Sin embargo, quiero: 1,2,3,4,5
¿Cómo puedo lograr eso de una manera elegante ?
Veo que hay cierta confusión acerca de lo que quiero decir con "elegante": por ejemplo, no ralentizar "if-clause" en mi ciclo. ¡Imagine 100.000 entradas en el vector! Si eso es todo lo que tienes para ofrecer, preferiría eliminar la última coma después de pasar por el ciclo.
Detectar el anterior es siempre complicado, detectar el primero es muy fácil.
bool first = true;
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
if (!first) { ss << ","; }
first = false;
ss << i;
}
Esto funcionaría
stringstream ss;
BOOST_FOREACH(int const& i, VecInts)
{
if(&i != &VecInts[0])
ss << ", ";
ss << i;
}
Sospecho que con "elegante" quieres decir "sin introducir una nueva variable". Pero creo que simplemente lo haría "no elegante" si no pudiera encontrar nada más. Todavía está claro
stringstream ss;
bool comma = false;
BOOST_FOREACH(int i, VecInts)
{
if(comma)
ss << ", ";
ss << i;
comma = true;
}
¡Imagine 100.000 entradas en el vector! Si eso es todo lo que tienes que ofrecer, preferiría eliminar la última coma después de haber completado el ciclo.
Usted está diciendo que si imprimir ss << i
es una instrucción de máquina. Vamos, ejecutando esa expresión se ejecutarán montones de if
y bucles dentro. Tu if
no será nada en comparación con eso.
Me gusta mover la prueba fuera del circuito.
Solo necesita hacerse una vez. Entonces hazlo primero.
Me gusta esto:
if (!VecInts.empty())
{
ss << VecInts[0]
for(any loop = ++(VecInts.begin()); loop != VecInts.end(); ++loop)
{
ss << "," << *loop;
}
}
Personalmente, me gusta una solución que no cause posibles asignaciones de memoria (porque la cadena crece más de lo necesario). Un extra-si dentro del cuerpo del bucle debería ser manejable gracias al almacenamiento en búfer de destino de bifurcación, pero yo lo haría:
#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;
}
}
Alternativamente, BYORA (traiga su propio algoritmo reutilizable):
// 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, ", ");
}
así que eso
...
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;
...
salida:
5, 1, 4, 2, 3
5-1-4-2-3
5> <1> <4> <2> <3
Lo bueno es que funciona para cada flujo de salida, cualquier contenedor que tenga iteradores directos, con cualquier infijo, y con cualquier tipo de infijo (interesante, por ejemplo, cuando se usan cadenas anchas).
Puede recortar la cadena al final o usar single for loop en lugar de foreach y no concatenar en la última iteración
Qué tal esto:
#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 es necesario agregar variables adicionales y ni siquiera depende de boost! En realidad, además del requisito de "ninguna variable adicional en el ciclo", se podría decir que ni siquiera hay un ciclo :)
Tratar:
if (ss.tellp ())
{
ss << ",";
}
ss << i;
Alternativamente, si el "si" te está preocupando:
char *comma = "";
BOOST_FOREACH(int i, VecInts)
{
ss << comma << i;
comma = ",";
}
Usando Karma de Boost Spirit, tiene una reputación de ser rápido.
#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;
}
cout << ss.str()<<"/b" <<" ";
Puede agregar el retroceso "/ b"
Esto sobrescribirá el "," adicional.
por ejemplo :
int main()
{
cout<<"Hi";
cout<<''/b''; //Cursor moves 1 position backwards
cout<<" "; //Overwrites letter ''i'' with space
}
Entonces la salida sería
H