2010-02-20 6 views
9

Como sé que C++ sólo permite añadir 2 cadenas juntas, es decir: s = s1 + s2Cómo agregar muchas cadenas en C++

Pero, ¿cómo puedo añadir muchas cadenas juntas? Me gusta:

s = s1 + s2 + s3 + s4 + ... + sn 
+9

¿Por qué crees que esto no funciona? – bmargulies

+1

¿estás usando la clase de cuerda? – cpx

+0

sí, me di cuenta de que funciona solo cuando uso la clase de cadena. pero quiero hacer algo como esto en C++ #define St "blah3" s = s1 + "blah1" + "blah2" + St – root

Respuesta

8

Si usted está tratando de agregar objetos de cadena de clase std :: string, esto debería funcionar.

string s1 = "string1"; 
string s2 = "string2"; 
string s3 = "string3"; 

string s = s1 + s2 + s3; 

O

string s = string("s1") + string("s2") + string("s3") ... 
+6

1 - Hemos de tener en cuenta cuando se utiliza 'operador + (std :: basic_string , std :: basic_string )' se incurrirá en tiempo exponencial en C++ 03. El uso de la función de miembro 'std :: basic_string :: append' solo toma tiempo lineal en comparación. –

+0

Creo que string s = string ("s1") + cadena ("s2") + cadena ("s3") ... es algo que estoy buscando. Me pregunto por qué funciona? – root

+2

Como eres cuando usas string (x), invocas un constructor para la clase de cadena estándar en x. Usted crea un objeto de cadena temporal que luego puede participar con su operador +. (Este tipo de obras como una forma de reparto) –

7

En primer lugar, puede hacer lo + sn bien. Aunque tardará exponencial quadradic (ver comentarios) tiempo suponiendo que está utilizando std::basic_string<t> cadenas en C++ 03.

Puede usar el std::basic_string<t>::append junto con std::basic_string<t>::reserve para concatenar su cadena en el tiempo O (n).

EDIT: Por ejemplo

string a; 
//either 
a.append(s1).append(s2).append(s3); 
//or 
a.append("I'm a string!").append("I am another string!"); 
+1

No tomará tiempo exponencial, solo cuadrático. 'append' será más rápido, pero en general cuadrático de todos modos, ya que necesita reasignar formulario de vez en cuando. Sin embargo, en la mayoría de los casos, ambos métodos no serán lo suficientemente lentos para ser perceptibles. – sth

+0

No, en realidad es exponencial, como lo demuestra la respuesta de R Samuel Klatchko. Agregue s1 y s2 juntos, luego agregue el resultado a s3, luego agregue el resultado a s4 ... etc. Cada adición agrega la longitud completa de todas las cadenas anteriores de la secuencia. Por lo tanto, dadas las K cadenas de longitud N, tendrás Sum_ {i = 1}^{K} (Sum_ {j = 1}^{i - 1} (N) + N) que es exponencial. 'Std :: :: basic_string append' es lineal si se usa con' std :: :: basic_string reserve' como se dice en mi respuesta, porque 'std :: basic_string garantías :: reserve' ninguna reasignación. –

+0

Nota: Es cuadrúdica con respecto a K en mi ejemplo anterior, pero exponencial con respecto a N, por lo que ambos estamos correctos aquí si miras el problema de otra manera. –

4
s = s1 + s2 + s3 + .. + sn; 

funcionará aunque se podría crear una gran cantidad de provisionales (un buen compilador de optimización debería ayudar), ya que efectivamente se interpretará como:

string tmp1 = s1 + s2; 
string tmp2 = tmp1 + s3; 
string tmp3 = tmp2 + s4; 
... 
s = tmpn + sn; 

Una manera alternativa que garantiza no crear temporari ES es:

s = s1; 
s += s2; 
s += s3; 
... 
s += sn; 
+0

Su ejemplo no es exactamente el mismo tmp1 debe ser copiado. Sería lo mismo si tmp1 fuera 'string const &'. Aunque debo admitir que RVO probablemente eliminaría la copia. –

3

std::ostringstream es construir para ello, véase el ejemplo here. Es muy fácil:

std::ostringstream out; 
out << "a" << "b" << "c" << .... << "z"; 
std::string str(out.str()); 
+1

Me gustaría señalar que el uso de stringstream para anexar cadenas es más lento que simplemente agregar a una cadena. stringstream es ideal para convertir cosas en cadenas, pero si lo único que estás haciendo es construir cadenas a partir de cadenas, entonces es la forma menos eficiente de hacerlo. append() y + = son el camino a seguir. –

+0

Sí, tienes razón. Una copia extra al menos. –

+1

En realidad, me escribió un programa de prueba para él recientemente y se encontró que tomó cerca de 2 1/2 veces más tiempo para poner las cuerdas junto con stringstream de anexar directamente a una cadena - y eso es _without_ conseguir la cadena fuera de la stringstream cuando' re hecho. Esa cifra en particular probablemente no sea precisa en circunstancias variables y todo eso, pero estaba bastante claro que la construcción de flujos con cadenas de caracteres es significativamente más lenta que la simple adición a una cadena. –

1

utilizar una plantilla para agregar cadenas, char * y carbón de formar una cadena

strlen: -

#include <iostream> 
#include <cstring> 

// it_pair to wrap a pair of iterators for a for(:) loop 
template<typename IT> 
class it_pair 
    { 
    IT b; 
    IT e; 
public: 
    auto begin() const 
     { 
     return b; 
     } 
    auto end() const 
     { 
     return e; 
     } 
    }; 

// string length 
template<typename S> auto strlen(const S& s) -> decltype(s.size()) 
    { 
    return s.size(); 
    } 

auto strlen(char c) -> size_t 
    { 
    return 1u; 
    } 

auto strlen(const std::initializer_list<char>& il) -> size_t 
    { 
    return il.size(); 
    } 

template<typename IT> 
auto strlen(const it_pair<IT>& p) 
    { 
    auto len = size_t{}; 
    for(const auto& s:p) 
     len += strlen(s); 
    return len; 
    } 

template<typename S, typename ...SS> auto strlen(S s, SS&... ss) -> size_t 
    { 
    return strlen(s) + strlen(ss...); 
    } 

cadenas anexas

// terminate recursion 
template<typename TA, typename TB> 
void append(TA& a, TB& b) 
    { 
    a.append(b); 
    } 

// special case for a character 
template<> 
void append<std::string, const char>(std::string& a, const char& b) 
    { 
    a.append(1, b); 
    } 

// special case for a collection of strings 
template<typename TA, typename TB> 
void append(TA& a, const it_pair<TB>& p) 
    { 
    for(const auto& x: p) 
     a.append(x); 
    } 

// recursion append 
template<typename TA, typename TB, typename ...TT> 
void append(TA& a, TB& b, TT&... tt) 
    { 
    append(a, b); 
    append(a, tt...); 
    } 

template<typename ...TT> 
std::string string_add(const TT& ... tt) 
    { 
    std::string s; 
    s.reserve(strlen(tt...)); 
    append(s, tt...); 
    return s; 
    } 

template<typename IT> 
auto make_it_pair(IT b, IT e) 
    { 
    return it_pair<IT>{b, e}; 
    } 

template<typename T> 
auto make_it_pair(const T& t) 
    { 
    using namespace std; 
    return make_it_pair(cbegin(t), cend(t)); 
    } 

ejemplo principal

int main() 
    { 
    const char * s[] = {"vw", "xyz"}; 
    std::vector<std::string> v{"l", "mn", "opqr"}; 
    std::string a("a"); 
    std::string b("bc"); 
    std::string c("def"); 
    std::cout << string_add(a, b+c, "ghij", make_it_pair(v), 'k', make_it_pair(s)); 
    } 
+0

Deberías crear una propuesta para la estandarización :) –