Jak połączyć std :: string i int?


655

Myślałem, że to będzie naprawdę proste, ale wiąże się to z pewnymi trudnościami. Jeżeli mam

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

Jak je połączyć, aby uzyskać pojedynczy ciąg "John21"?


Herb Sutter ma dobry artykuł na ten temat: „The String Formatters of Manor Farm” . Obejmuje on Boost::lexical_cast, std::stringstream, std::strstream(która jest przestarzała), a sprintfw porównaniu snprintf.
Fred Larson,

Dodaję do tego: próbowałem „str =" hi "; str + = 5; cout << str; ' i nie widziałem żadnego efektu. Okazuje się, że to wywołuje operator + = (char) i dodaje znak, który nie może zostać wydrukowany.
daveagp

Odpowiedzi:


1125

W porządku alfabetycznym:

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. jest bezpieczny, ale wolny; wymaga wzmocnienia (tylko nagłówek); większość / wszystkie platformy
  2. jest bezpieczny, wymaga C ++ 11 ( to_string () jest już zawarte w #include <string>)
  3. jest bezpieczny i szybki; wymaga FastFormat , który należy skompilować; większość / wszystkie platformy
  4. (to samo )
  5. jest bezpieczny i szybki; wymaga biblioteki {fmt} , którą można skompilować lub użyć w trybie tylko nagłówka; większość / wszystkie platformy
  6. bezpieczny, wolny i pełny; wymaga #include <sstream>(od standardowego C ++)
  7. jest kruchy (musisz podać wystarczająco duży bufor), szybki i pełny; itoa () jest niestandardowym rozszerzeniem i nie ma gwarancji, że będzie dostępny na wszystkich platformach
  8. jest kruchy (musisz podać wystarczająco duży bufor), szybki i pełny; nie wymaga niczego (jest standardowym C ++); wszystkie platformy
  9. jest kruchy (musisz podać wystarczająco duży bufor), prawdopodobnie najszybsza możliwa konwersja , pełna; wymaga STLSoft (tylko nagłówek); większość / wszystkie platformy
  10. safe-ish (nie używasz więcej niż jednego wywołania int_to_string () w jednej instrukcji), szybko; wymaga STLSoft (tylko nagłówek); Tylko dla systemu Windows
  11. jest bezpieczny, ale wolny; wymaga Poco C ++ ; większość / wszystkie platformy

13
Oprócz jednego linku, który podałeś, na czym opierasz swoje komentarze dotyczące wydajności?
JamieH

2
To prawie cała twoja reputacja z jednej odpowiedzi !! You lucky bean;) Myślę, że 8 to standardowy C (oczywiście także C ++), ale prawdopodobnie warto go rozróżnić.
noelicus

2. jest wolny, ponieważ std :: to_string (wiek) tworzy tymczasowy ciąg, który jest dołączany do wyniku.
Igor Bukanov,

Jeśli korzystasz z Arduino, możesz także użyć String(number).
Machado

267

W C ++ 11 możesz użyć std::to_stringnp .:

auto result = name + std::to_string( age );

podoba mi się ten, prosty. Dzięki.
truthadjustr

85

Jeśli masz Boost, możesz przekonwertować liczbę całkowitą na ciąg za pomocą boost::lexical_cast<std::string>(age).

Innym sposobem jest użycie strumieni ciągów:

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

Trzecim podejściem byłoby użycie sprintflub snprintfz biblioteki C.

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

Inne plakaty sugerują użycie itoa. To NIE jest standardowa funkcja, więc kod nie będzie przenośny, jeśli go użyjesz. Istnieją kompilatory, które tego nie obsługują.


Zauważ, że snprintf nie gwarantuje, że łańcuch zakończy się zerem. Oto jeden ze sposobów, aby upewnić się, że działa: <pre> char buffer [128]; bufor [sizeof (bufor) -1] = '\ 0'; snprintf (bufor, rozmiarof (bufor) -1, "% s% d", name.c_str (), wiek); std :: cout << bufor << std :: endl; </pre>
Pan Fooz,

Moją tendencją byłoby nigdy nie używać sprintf, ponieważ może to spowodować przepełnienie bufora. Powyższy przykład jest dobrym przykładem, w którym użycie sprintf byłoby niebezpieczne, gdyby nazwa była bardzo długa.
terson

zauważ, że snprintf jest równie niestandardowym językiem c ++ (jak itoa, o którym wspomniałeś). pochodzi z c99
Johannes Schaub - litb

@terson: Tylko nie widzę sprintfodpowiedzi snprintf.
David Foerster

80
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();

2
to jest wielki, nagłówek pliku BYT jest 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();
}

Bezwstydnie skradziony z http://www.research.att.com/~bs/bs_faq2.html .


ale s zmienne stosu, pamięć sbędzie wolna po wywołaniu itos. snależy przydzielić ze sterty, a freepo użyciu, prawda?
kgbook

1
zwracanie przez wartość jest w porządku, mimo że obiekt łańcucha wykroczył poza zakres, stackoverflow.com/a/3977119/5393174
kgbook 10.09.2018


23

Jeśli masz C ++ 11, możesz użyć std::to_string.

Przykład:

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

name += std::to_string(age);

std::cout << name;

Wynik:

John21

2
Byłoby to name += std::to_string(static_cast<long long>(age));w VC ++ 2010, jak widać tutaj
neonmate

@neonmate A może name += std::to_string(age + 0LL);zamiast tego?
chux - Przywróć Monikę

18

Wydaje mi się, że najprostszą odpowiedzią jest użycie sprintffunkcji:

sprintf(outString,"%s%d",name,age);

1
snprintf może być trudny (głównie dlatego, że w niektórych sytuacjach potencjalnie nie może zawierać znaku zerowego), ale wolę, aby uniknąć przepełnienia bufora sprintf potencjalnych problemów.
terson

3
sprintf (char *, const char *, ...) zawiedzie w niektórych wersjach kompilatorów, gdy przekażesz std :: string do% s. Jednak nie wszystkie (jest to niezdefiniowane zachowanie) i może zależeć od długości ciągu (SSO). Proszę użyć .c_str ()
MSalters

plus sprintf podlega przepełnieniu bufora, więc możliwe wstrzyknięcie kodu
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();
}

11
#include <sstream>

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

Wtedy twoje użycie wyglądałoby mniej więcej tak

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

Googled [i przetestowałem: p]


10

Ten problem można rozwiązać na wiele sposobów. Pokażę to na dwa sposoby:

  1. Konwertuj liczbę na ciąg za pomocą to_string(i).

  2. Korzystanie ze strumieni ciągów.

    Kod:

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

Który jest szybszy?
GyuHyeon Choi

7

Jeśli chcesz użyć +do konkatenacji czegokolwiek, co ma operator wyjściowy, możesz podać wersję szablonu operator+:

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

Następnie możesz napisać swoje konkatenacje w prosty sposób:

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

Wynik:

the answer is 42

To nie jest najbardziej efektywny sposób, ale nie potrzebujesz najbardziej wydajnego sposobu, chyba że wykonujesz dużo konkatenacji w pętli.


Jeśli spróbuję dodać do liczb całkowitych lub liczby całkowitej i podwójnej, czy ta funkcja zostanie wywołana? Zastanawiam się, czy to rozwiązanie zastąpi zwykłe dodatki ...
Hilder Vitor Lima Pereira

Operator zwraca a std::string, więc nie byłby kandydatem w wyrażeniach, w których ciągu nie można zamienić na potrzebny typ. Np. operator+Nie można tego wykorzystać +w int x = 5 + 7;. Biorąc wszystko pod uwagę, nie zdefiniowałbym takiego operatora bez bardzo ważnego powodu, ale moim celem było zaoferowanie odpowiedzi innej niż pozostałe.
uckelman

Masz rację (właśnie to przetestowałem ...). A kiedy próbowałem zrobić coś takiego jak ciąg s = 5 + 7 , otrzymałem błąd niepoprawnej konwersji z „int” na „const char ” *
Hilder Vitor Lima Pereira


4

Std :: ostringstream jest dobrą metodą, ale czasami ta dodatkowa sztuczka może się przydać, przekształcając formatowanie w jednowierszowe:

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

Teraz możesz sformatować ciągi takie jak to:

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

4

Ponieważ pytanie dotyczące Qt zostało zamknięte na korzyść tego, oto jak to zrobić za pomocą Qt:

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

Zmienna łańcuchowa ma teraz wartość someIntVariable zamiast% 1 i wartość someOtherIntVariable na końcu.


Działa także QString („Coś”) + QString :: number (someIntVariable)
gremwell,

3

Istnieje więcej opcji, których można użyć do połączenia liczby całkowitej (lub innego obiektu numerycznego) z ciągiem znaków. To jest 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);
}

i Karma z 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 twierdzi, że jest jedną z najszybszych opcji konwersji liczby całkowitej na ciąg znaków .



3

Możesz połączyć int z ciągiem znaków, używając podanej poniżej prostej sztuczki, ale pamiętaj, że działa to tylko wtedy, gdy liczba całkowita jest jednocyfrowa. W przeciwnym razie dodaj liczbę całkowitą cyfra po cyfrze do tego ciągu.

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

Output:  John5

2

Oto implementacja sposobu dodawania int do ciągu przy użyciu aspektów parsowania i formatowania z biblioteki IOStreams.

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

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

Który jest najszybszy?
GyuHyeon Choi

2

Jest funkcja, którą napisałem, która przyjmuje liczbę int jako parametr i konwertuje ją na literał łańcuchowy. Ta funkcja zależy od innej funkcji, która konwertuje pojedynczą cyfrę na jej równoważnik char:

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

1

Z biblioteką {fmt} :

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

Podzbiór biblioteki jest proponowany do standaryzacji jako formatowanie tekstu P0645, a jeśli zostanie zaakceptowany, powyższe stanie się:

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

Oświadczenie : Jestem autorem biblioteki {fmt}.


0

Jako jedna wkładka: name += std::to_string(age);


3
To ten sam kod, co w odpowiedzi 0x499602D2.
BDL
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.