Wie verkette ich einen std :: string und einen int?

655

Ich dachte, das wäre wirklich einfach, aber es bringt einige Schwierigkeiten mit sich. Wenn ich habe

std::string name = "John";
int age = 21;

Wie kombiniere ich sie, um eine einzelne Zeichenfolge zu erhalten "John21"?

Obediah Stane
quelle
Herb Sutter hat einen guten Artikel zu diesem Thema: "The String Formatters of Manor Farm" . Er deckt Boost::lexical_cast, std::stringstream, std::strstream(was veraltet ist), und sprintfgegen snprintf.
Fred Larson
Lassen Sie mich noch etwas hinzufügen: Ich habe 'str = "hi" ausprobiert; str + = 5; cout << str; ' und sah keine Wirkung. Es stellt sich heraus, dass dies den Operator + = (char) aufruft und ein nicht druckbares Zeichen hinzufügt.
Daveagp

Antworten:

1125

In alphabetischer Reihenfolge:

std::string name = "John";
int age = 21;
std::string result;

// 1. with Boost
result = name + boost::lexical_cast<std::string>(age);

// 2. with C++11
result = name + std::to_string(age);

// 3. with FastFormat.Format
fastformat::fmt(result, "{0}{1}", name, age);

// 4. with FastFormat.Write
fastformat::write(result, name, age);

// 5. with the {fmt} library
result = fmt::format("{}{}", name, age);

// 6. with IOStreams
std::stringstream sstm;
sstm << name << age;
result = sstm.str();

// 7. with itoa
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + itoa(age, numstr, 10);

// 8. with sprintf
char numstr[21]; // enough to hold all numbers up to 64-bits
sprintf(numstr, "%d", age);
result = name + numstr;

// 9. with STLSoft's integer_to_string
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + stlsoft::integer_to_string(numstr, 21, age);

// 10. with STLSoft's winstl::int_to_string()
result = name + winstl::int_to_string(age);

// 11. With Poco NumberFormatter
result = name + Poco::NumberFormatter().format(age);
  1. ist sicher, aber langsam; erfordert Boost (nur Header); die meisten / alle Plattformen
  2. ist sicher, erfordert C ++ 11 ( to_string () ist bereits enthalten in #include <string>)
  3. ist sicher und schnell; erfordert FastFormat , das kompiliert werden muss; die meisten / alle Plattformen
  4. ( dito )
  5. ist sicher und schnell; erfordert die {fmt} -Bibliothek , die entweder kompiliert oder nur im Header-Modus verwendet werden kann; die meisten / alle Plattformen
  6. sicher, langsam und ausführlich; erfordert #include <sstream>(von Standard C ++)
  7. ist spröde (Sie müssen einen ausreichend großen Puffer bereitstellen), schnell und ausführlich; itoa () ist eine nicht standardmäßige Erweiterung und nicht garantiert für alle Plattformen verfügbar
  8. ist spröde (Sie müssen einen ausreichend großen Puffer bereitstellen), schnell und ausführlich; erfordert nichts (ist Standard C ++); alle Plattformen
  9. ist spröde (Sie müssen einen ausreichend großen Puffer bereitstellen), wahrscheinlich die schnellstmögliche Konvertierung , ausführlich; erfordert STLSoft (nur Header); die meisten / alle Plattformen
  10. safe-ish (Sie verwenden nicht mehr als einen Aufruf von int_to_string () in einer einzelnen Anweisung), fast; erfordert STLSoft (nur Header); Nur Windows
  11. ist sicher, aber langsam; erfordert Poco C ++ ; die meisten / alle Plattformen
DannyT
quelle
13
Worauf stützen Sie Ihre Leistungskommentare, abgesehen von dem einen Link, den Sie angegeben haben?
JamieH
2
Das ist fast Ihr ganzer Ruf mit einer einzigen Antwort! Du Glücksbohne;) Ich denke 8 ist Standard C (natürlich auch C ++), aber es lohnt sich wahrscheinlich zu differenzieren.
Noelicus
2. ist langsam, da std :: to_string (age) eine temporäre Zeichenfolge erstellt, die an das Ergebnis angehängt wird.
Igor Bukanov
Wenn Sie auf Arduino sind, können Sie auch verwenden String(number).
Machado
266

In C ++ 11 können Sie Folgendes verwenden std::to_string: z.

auto result = name + std::to_string( age );
Jeremy
quelle
Ich mag dieses, einfach. Vielen Dank.
Truthadjustr
85

Wenn Sie Boost haben, können Sie die Ganzzahl mit in eine Zeichenfolge konvertieren boost::lexical_cast<std::string>(age).

Eine andere Möglichkeit ist die Verwendung von Stringstreams:

std::stringstream ss;
ss << age;
std::cout << name << ss.str() << std::endl;

Ein dritter Ansatz wäre die Verwendung von sprintfoder snprintfaus der C-Bibliothek.

char buffer[128];
snprintf(buffer, sizeof(buffer), "%s%d", name.c_str(), age);
std::cout << buffer << std::endl;

Andere Poster empfehlen die Verwendung itoa. Dies ist KEINE Standardfunktion, daher ist Ihr Code nicht portierbar, wenn Sie ihn verwenden. Es gibt Compiler, die dies nicht unterstützen.

Jay Conrod
quelle
Beachten Sie, dass snprintf die Zeichenfolge nicht mit Null beenden kann. Hier ist eine Möglichkeit, um sicherzustellen, dass es funktioniert: <pre> char buffer [128]; buffer [sizeof (buffer) -1] = '\ 0'; snprintf (Puffer, Größe von (Puffer) -1, "% s% d", name.c_str (), Alter); std :: cout << buffer << std :: endl; </ pre>
Herr Fooz
Meine Tendenz wäre, niemals sprintf zu verwenden, da dies zu Pufferüberläufen führen kann. Das obige Beispiel ist ein gutes Beispiel, bei dem die Verwendung von sprintf unsicher wäre, wenn der Name sehr lang wäre.
Terson
Beachten Sie, dass snprintf ebenfalls kein Standard-C ++ ist (wie das von Ihnen erwähnte itoa). es ist aus c99
Johannes Schaub - litb
@terson: Ich sehe sprintfnur in der Antwort kein Vorkommen von snprintf.
David Foerster
80
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();
Ben Hoffstein
quelle
2
Das ist großartig, BYT-Header-Datei ist sstream
landerlyoung
52
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string itos(int i) // convert int to string
{
    stringstream s;
    s << i;
    return s.str();
}

Schamlos gestohlen von http://www.research.att.com/~bs/bs_faq2.html .

tloach
quelle
Da s es sich jedoch um eine Stapelvariable handelt, ist der Speicher von snach dem Aufruf frei itos. ssollte vom Haufen zuordnen, und freenach der Verwendung, richtig?
kgbook
1
Die Rückgabe nach Wert ist in Ordnung, obwohl das Zeichenfolgenobjekt den Gültigkeitsbereich verlassen hat. stackoverflow.com/a/3977119/5393174
kgbook
32

Dies ist der einfachste Weg:

string s = name + std::to_string(age);
Kevin
quelle
8
Dies ist eine Post-C ++ 11-Lösung!
YamHon.CHAN
23

Wenn Sie C ++ 11 haben, können Sie verwenden std::to_string.

Beispiel:

std::string name = "John";
int age = 21;

name += std::to_string(age);

std::cout << name;

Ausgabe:

John21
0x499602D2
quelle
2
Es wäre name += std::to_string(static_cast<long long>(age));in VC ++ 2010, wie Sie hier sehen können
Neonmate
@neonmate Wie wäre es name += std::to_string(age + 0LL);stattdessen?
chux
18

Es scheint mir, dass die einfachste Antwort darin besteht, die sprintfFunktion zu verwenden:

sprintf(outString,"%s%d",name,age);
user12576
quelle
1
snprintf kann schwierig sein (hauptsächlich, weil es in bestimmten Situationen möglicherweise nicht das Nullzeichen enthalten kann), aber ich bevorzuge dies, um zu vermeiden, dass der Sprintf-Puffer potenzielle Probleme überläuft.
Terson
3
sprintf (char *, const char *, ...) schlägt bei einigen Compilerversionen fehl, wenn Sie% s einen std :: string übergeben. Nicht alle (es ist undefiniertes Verhalten) und es kann von der Stringlänge (SSO) abhängen. Bitte benutzen Sie .c_str ()
MSalters
plus sprintf unterliegt Pufferüberläufen, so dass eine mögliche Code-Injektion möglich ist
Jean-François Fabre
15
#include <string>
#include <sstream>
using namespace std;
string concatenate(std::string const& name, int i)
{
    stringstream s;
    s << name << i;
    return s.str();
}
Seb Rose
quelle
11
#include <sstream>

template <class T>
inline std::string to_string (const T& t)
{
   std::stringstream ss;
   ss << t;
   return ss.str();
}

Dann würde Ihre Nutzung ungefähr so ​​aussehen

   std::string szName = "John";
   int numAge = 23;
   szName += to_string<int>(numAge);
   cout << szName << endl;

Googelte [und testete: p]

Zing-
quelle
10

Dieses Problem kann auf viele Arten gelöst werden. Ich werde es auf zwei Arten zeigen:

  1. Konvertieren Sie die Zahl mit in eine Zeichenfolge to_string(i).

  2. Verwenden von String-Streams.

    Code:

    #include <string>
    #include <sstream>
    #include <bits/stdc++.h>
    #include <iostream>
    using namespace std;
    
    int main() {
        string name = "John";
        int age = 21;
    
        string answer1 = "";
        // Method 1). string s1 = to_string(age).
    
        string s1=to_string(age); // Know the integer get converted into string
        // where as we know that concatenation can easily be done using '+' in C++
    
        answer1 = name + s1;
    
        cout << answer1 << endl;
    
        // Method 2). Using string streams
    
        ostringstream s2;
    
        s2 << age;
    
        string s3 = s2.str(); // The str() function will convert a number into a string
    
        string answer2 = "";  // For concatenation of strings.
    
        answer2 = name + s3;
    
        cout << answer2 << endl;
    
        return 0;
    }
lohith99
quelle
Welches ist schneller?
GyuHyeon Choi
7

Wenn Sie +für die Verkettung von Elementen mit einem Ausgabeoperator verwenden möchten, können Sie eine Vorlagenversion von Folgendem bereitstellen operator+:

template <typename L, typename R> std::string operator+(L left, R right) {
  std::ostringstream os;
  os << left << right;
  return os.str();
}

Dann können Sie Ihre Verkettungen auf einfache Weise schreiben:

std::string foo("the answer is ");
int i = 42;
std::string bar(foo + i);    
std::cout << bar << std::endl;

Ausgabe:

the answer is 42

Dies ist nicht der effizienteste Weg, aber Sie benötigen den effizientesten Weg nur, wenn Sie innerhalb einer Schleife viel Verkettung durchführen.

uckelman
quelle
Wird diese Funktion aufgerufen, wenn ich versuche, Ganzzahlen oder eine Ganzzahl und ein Doppel zu addieren? Ich frage mich, ob diese Lösung die üblichen Ergänzungen außer Kraft setzen wird ...
Hilder Vitor Lima Pereira
Der Operator gibt a zurück std::stringund wäre daher kein Kandidat für Ausdrücke, bei denen eine Zeichenfolge nicht in den erforderlichen Typ konvertierbar ist. ZB das operator+verwendet werden soll , nicht für eine +in int x = 5 + 7;. Alles in allem würde ich einen solchen Operator nicht ohne einen sehr zwingenden Grund definieren, aber mein Ziel war es, eine andere Antwort als die anderen anzubieten.
uckelman
Sie haben Recht (ich habe es gerade getestet ...). Und als ich versuchte, so etwas wie String s = 5 + 7 zu machen , bekam ich den Fehler ungültige Konvertierung von 'int' nach 'const char ' *
Hilder Vitor Lima Pereira
5

Wenn Sie MFC verwenden, können Sie einen CString verwenden

CString nameAge = "";
nameAge.Format("%s%d", "John", 21);

Managed C ++ hat auch einen String-Formatierer .

bsruth
quelle
4

Der std :: ostringstream ist eine gute Methode, aber manchmal kann dieser zusätzliche Trick nützlich sein, um die Formatierung in einen Einzeiler umzuwandeln:

#include <sstream>
#define MAKE_STRING(tokens) /****************/ \
    static_cast<std::ostringstream&>(          \
        std::ostringstream().flush() << tokens \
    ).str()                                    \
    /**/

Jetzt können Sie Zeichenfolgen wie folgt formatieren:

int main() {
    int i = 123;
    std::string message = MAKE_STRING("i = " << i);
    std::cout << message << std::endl; // prints: "i = 123"
}
Pyry Jahkola
quelle
4

Da eine Qt-bezogene Frage zugunsten dieser Frage geschlossen wurde, gehen Sie wie folgt vor, um Qt zu verwenden:

QString string = QString("Some string %1 with an int somewhere").arg(someIntVariable);
string.append(someOtherIntVariable);

Die Zeichenfolgenvariable hat jetzt den Wert von someIntVariable anstelle von% 1 und den Wert von someOtherIntVariable am Ende.

leinir
quelle
QString ("Something") + QString :: number (someIntVariable) funktioniert auch
Gremwell
3

Es gibt weitere Optionen, mit denen Ganzzahlen (oder andere numerische Objekte) mit Zeichenfolgen verknüpft werden können. Es ist Boost.Format

#include <boost/format.hpp>
#include <string>
int main()
{
    using boost::format;

    int age = 22;
    std::string str_age = str(format("age is %1%") % age);
}

und Karma von Boost.Spirit (v2)

#include <boost/spirit/include/karma.hpp>
#include <iterator>
#include <string>
int main()
{
    using namespace boost::spirit;

    int age = 22;
    std::string str_age("age is ");
    std::back_insert_iterator<std::string> sink(str_age);
    karma::generate(sink, int_, age);

    return 0;
}

Boost.Spirit Karma behauptet, eine der schnellsten Optionen für die Konvertierung von Ganzzahlen in Zeichenfolgen zu sein .

Mloskot
quelle
3

Sie können int mit dem folgenden einfachen Trick zu einem String verketten. Beachten Sie jedoch, dass dies nur funktioniert, wenn die Ganzzahl einstellig ist. Andernfalls fügen Sie dieser Zeichenfolge eine ganzzahlige Ziffer für Ziffer hinzu.

string name = "John";
int age = 5;
char temp = 5 + '0';
name = name + temp;
cout << name << endl;

Output:  John5
Sukhbir
quelle
2

Hier finden Sie eine Implementierung zum Anhängen eines Int an eine Zeichenfolge mithilfe der Parsing- und Formatierungsfacetten aus der IOStreams-Bibliothek.

#include <iostream>
#include <locale>
#include <string>

template <class Facet>
struct erasable_facet : Facet
{
    erasable_facet() : Facet(1) { }
    ~erasable_facet() { }
};

void append_int(std::string& s, int n)
{
    erasable_facet<std::num_put<char,
                                std::back_insert_iterator<std::string>>> facet;
    std::ios str(nullptr);

    facet.put(std::back_inserter(s), str,
                                     str.fill(), static_cast<unsigned long>(n));
}

int main()
{
    std::string str = "ID: ";
    int id = 123;

    append_int(str, id);

    std::cout << str; // ID: 123
}
0x499602D2
quelle
2
  • std :: ostringstream
#include <sstream>

std::ostringstream s;
s << "John " << age;
std::string query(s.str());
  • std :: to_string (C ++ 11)
std::string query("John " + std::to_string(age));
  • boost :: lexical_cast
#include <boost/lexical_cast.hpp>

std::string query("John " + boost::lexical_cast<std::string>(age));
Isma Rekathakusuma
quelle
Welches ist das schnellste?
GyuHyeon Choi
2

Ich habe eine Funktion geschrieben, die die int-Nummer als Parameter verwendet und in ein String-Literal konvertiert. Diese Funktion hängt von einer anderen Funktion ab, die eine einzelne Ziffer in ihr Zeichenäquivalent konvertiert:

char intToChar(int num)
{
    if (num < 10 && num >= 0)
    {
        return num + 48;
        //48 is the number that we add to an integer number to have its character equivalent (see the unsigned ASCII table)
    }
    else
    {
        return '*';
    }
}

string intToString(int num)
{
    int digits = 0, process, single;
    string numString;
    process = num;

    // The following process the number of digits in num
    while (process != 0)
    {
        single  = process % 10; // 'single' now holds the rightmost portion of the int
        process = (process - single)/10;
        // Take out the rightmost number of the int (it's a zero in this portion of the int), then divide it by 10
        // The above combination eliminates the rightmost portion of the int
        digits ++;
    }

    process = num;

    // Fill the numString with '*' times digits
    for (int i = 0; i < digits; i++)
    {
        numString += '*';
    }


    for (int i = digits-1; i >= 0; i--)
    {
        single = process % 10;
        numString[i] = intToChar ( single);
        process = (process - single) / 10;
    }

    return numString;
}
Reda Lahdili
quelle
1

Mit der {fmt} Bibliothek :

auto result = fmt::format("{}{}", name, age);

Eine Teilmenge der Bibliothek wird zur Standardisierung als P0645-Textformatierung vorgeschlagen. Wenn dies akzeptiert wird, wird Folgendes angezeigt :

auto result = std::format("{}{}", name, age);

Haftungsausschluss : Ich bin der Autor der {fmt} -Bibliothek.

vitaut
quelle
0

Als Einzeiler: name += std::to_string(age);

ant_dev
quelle
3
Das ist der gleiche Code wie in der Antwort 0x499602D2.
BDL