Bir std :: string ve int birleştirmek nasıl?


655

Bunun gerçekten basit olacağını düşündüm ama bazı zorluklar içeriyor. Sahip olursam

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

Tek bir dize almak için bunları nasıl birleştiririm "John21"?


Herb Sutter'in bu konuda iyi bir makalesi var: "Manor Farm'ın String Formatters" . O kapsar Boost::lexical_cast, std::stringstream, std::strstream(kullanımdan kaldırıldı hangi) ve sprintfvs snprintf.
Fred Larson

Buna ekleyeyim: 'str = "hi" denedim; str + = 5; cout << str; ' ve hiçbir etki görmedi. Bu çağrıyı yapan operatör + = (karakter) ve yazdırılamayan bir karakter ekler.
daveagp

Yanıtlar:


1126

Alfabetik sırayla:

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. güvenli, ancak yavaş; Boost (yalnızca başlık) gerektirir ; çoğu / tüm platformlar
  2. güvenli, C ++ 11 gerektirir ( to_string () zaten dahil edilmiştir #include <string>)
  3. güvenli ve hızlı; derlenmesi gereken FastFormat gerektirir ; çoğu / tüm platformlar
  4. ( aynen )
  5. güvenli ve hızlı; {fmt} kütüphanesini gerektiriryalnızca üstbilgi modunda derlenebilen veya kullanılabilen ; çoğu / tüm platformlar
  6. güvenli, yavaş ve ayrıntılı; gerektirir #include <sstream>(standart C ++ 'tan)
  7. kırılgan (yeterince büyük bir tampon sağlamalısınız), hızlı ve ayrıntılı; itoa () standart olmayan bir uzantıdır ve tüm platformlar için kullanılabilir olduğu garanti edilmez
  8. kırılgan (yeterince büyük bir tampon sağlamalısınız), hızlı ve ayrıntılı; hiçbir şey gerektirmez (standart C ++ 'dır); tüm platformlar
  9. kırılgan (yeterince büyük bir tampon sağlamalısınız), muhtemelen en hızlı dönüşüm , ayrıntılı; STLSoft (yalnızca başlık) gerektirir ; çoğu / tüm platformlar
  10. safe-ish (tek bir ifadede birden fazla int_to_string () çağrısı kullanmazsınız ), hızlı; STLSoft gerektirir (yalnızca başlık) ; Windows yalnızca
  11. güvenli, ancak yavaş; Poco C ++ gerektirir ; çoğu / tüm platformlar

13
Verdiğiniz tek link dışında performans yorumlarınızı neye dayandırıyorsunuz?
JamieH

2
Tek bir cevaptan neredeyse tüm itibarınız !! Şanslı fasulye;) Bence 8 standart C (elbette C ++), ama muhtemelen farklılaşmaya değer.
noelicus

2. std :: to_string (age) sonuca eklenen geçici bir dize oluşturduğundan yavaştır.
Igor Bukanov

Arduino'daysanız da kullanabilirsiniz String(number).
Machado

267

C ++ 11'de şunları kullanabilirsiniz std::to_string:

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

Bunu beğendim, basit. Teşekkürler.
truthadjustr

85

Boost varsa, tamsayıyı kullanarak bir dizeye dönüştürebilirsiniz boost::lexical_cast<std::string>(age).

Başka bir yol da stringstreams kullanmaktır:

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

Üçüncü bir yaklaşım C kütüphanesinden sprintfveya snprintfC kütüphanesinden kullanmak olacaktır .

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

Kullanılması önerilen diğer posterler itoa. Bu standart bir işlev DEĞİLDİR, bu nedenle kodunuz taşınabilirse kullanılamaz. Onu desteklemeyen derleyiciler var.


Snprintf'in dizeyi boş olarak sonlandıracağını garanti etmiyoruz. İşte çalıştığından emin olmanın bir yolu: <pre> char buffer [128]; tampon [sizeof (tampon) -1] = '\ 0'; snprintf (tampon, sizeof (tampon) -1, "% s% d", ad.c_str (), yaş); std :: cout << tampon << std :: endl; </pre>
Bay Fooz

Benim eğilimim asla sprintf kullanmak olacaktır, çünkü bu arabellek taşmalarına neden olabilir. Yukarıdaki örnek, ad çok uzunsa sprintf kullanmanın güvensiz olacağı iyi bir örnektir.
terson

snprintf'in eşit derecede standart olmayan c ++ olduğunu unutmayın (bahsettiğiniz itoa gibi). c99
Johannes Schaub - litb'dan

@terson: Ben hiçbir oluşumunu bakın sprintfsadece cevap snprintf.
David Foerster

80
#include <iostream>
#include <sstream>

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

2
bu harika, BYT başlık dosyası 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();
}

Utanmadan http://www.research.att.com/~bs/bs_faq2.html adresinden çalındı .


ancak s bir yığın değişkenidir, sçağrıldıktan sonra belleği serbest kalır itos. söbekten ayırmalı ve freekullandıktan sonra, değil mi?
kgbook

1
değeriyle dönüş dize nesne kapsamı, dışarı gitmiş olsa bile tamam stackoverflow.com/a/3977119/5393174
kgbook

32

Bu en kolay yol:

string s = name + std::to_string(age);

8
Bu bir post-C ++ 11 çözümüdür!
YamHon.CHAN

23

C ++ 11'iniz varsa kullanabilirsiniz std::to_string.

Misal:

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

name += std::to_string(age);

std::cout << name;

Çıktı:

John21

2
Bu olacağını name += std::to_string(static_cast<long long>(age));gördüğünüz gibi 2010 VC ++, burada
neonmate

@neonmate name += std::to_string(age + 0LL);Bunun yerine?
chux - Monica'yı eski durumuna getir

18

Bana öyle geliyor ki en basit cevap sprintfişlevi kullanmaktır :

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

1
snprintf zor olabilir (esas olarak bazı durumlarda boş karakteri içermeyebileceğinden), ancak sprintf arabelleğinin olası sorunlardan taşmasını önlemek için tercih ederim.
terson

3
sprintf (char *, const char *, ...), bir std :: dizesini% s dizinine geçirdiğinizde derleyicilerin bazı sürümlerinde başarısız olur. Ancak hepsi değil (tanımsız davranış) ve dize uzunluğuna (TOA) bağlı olabilir. Lütfen .c_str ()
MSalters

artı sprintf arabellek taşmasına tabidir, bu nedenle olası kod enjeksiyonu
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();
}

O zaman kullanımınız böyle bir şey olurdu

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

Googled [ve test edildi: p]


10

Bu problem birçok şekilde yapılabilir. İki şekilde göstereceğim:

  1. Tuşunu kullanarak sayıyı dizeye dönüştürün to_string(i).

  2. Dize akışlarını kullanma.

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

Hangisi daha hızlı?
GyuHyeon Choi

7

Bir +çıktı operatörü olan herhangi bir şeyin birleştirilmesi için kullanmak isterseniz, aşağıdakilerin şablon sürümünü sağlayabilirsiniz operator+:

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

Ardından, birleştirme işlemlerinizi basit bir şekilde yazabilirsiniz:

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

Çıktı:

the answer is 42

Bu en etkili yol değildir, ancak bir döngü içinde çok fazla birleştirme yapmadıkça en etkili yol gerekmez.


Tamsayılara veya bir tamsayıya ve bir çifte eklemeye çalışırsam, bu işlev çağrılır mı? Bu çözümün olağan ilaveleri geçersiz kılacağını merak ediyorum ...
Hilder Vitor Lima Pereira

İşleç a döndürür std::string, dolayısıyla bir dizenin gerekli türe dönüştürülemediği ifadelerde bir aday olmaz. Örneğin, bu operator+için kullanılmak üzere uygun değil +içinde int x = 5 + 7;. Her şey düşünüldüğünde, çok cazip bir neden olmadan böyle bir operatör tanımlamazdım , ancak amacım diğerlerinden farklı bir cevap sunmaktı.
uckelman

Haklısın (sadece test ettim ...). Ve s = 5 + 7 dizesi gibi bir şey yapmaya çalıştığımda , 'int' den 'const char ' * geçersiz dönüşüm hatası aldım *
Hilder Vitor Lima Pereira


4

Std :: ostringstream iyi bir yöntemdir, ancak bazen bu ek hile, biçimlendirmeyi bir astara dönüştürmede kullanışlı olabilir:

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

Artık dizeleri şu şekilde biçimlendirebilirsiniz:

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

4

Qt ile ilgili bir soru bu lehine kapatıldığı için, Qt kullanarak nasıl yapılacağı aşağıda açıklanmıştır:

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

Dize değişkeni artık% 1 yerine someIntVariable'ın değerine ve sondaki someOtherIntVariable'ın değerine sahip.


QString ("Something") + QString :: number (
someIntVariable

3

Tamsayıyı (veya başka bir sayısal nesneyi) dize ile birleştirmek için daha fazla seçenek vardır. Öyle 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);
}

ve Boost'dan Karma.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;
}

Spirit Karma , tamsayıdan dizgeye dönüşüm için en hızlı seçeneklerden biri olduğunu iddia ediyor .



3

Aşağıdaki basit hileyi kullanarak int dizesini bitiştirebilirsiniz, ancak bunun yalnızca tamsayı tek basamaklı olduğunda çalıştığını unutmayın. Aksi takdirde, bu dizeye basamaklı tam sayı ekleyin.

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

Output:  John5

2

Burada, IOStreams kitaplığındaki ayrıştırma ve biçimlendirme yönlerini kullanarak bir dizeye int nasıl ekleneceğinin bir uygulamasıdır.

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

Hangisi en hızlı?
GyuHyeon Choi

2

Yazdığım, int numarasını parametre olarak alan ve onu bir dizgi değişmezine dönüştüren bir işlev var. Bu işlev, tek bir basamağı karakter eşdeğerine dönüştüren başka bir işleve bağlıdır:

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

İle {Fmt} kütüphanede :

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

Kütüphanenin bir alt kümesi P0645 Metin Biçimlendirmesi olarak standartlaştırma için önerilmiştir ve kabul edilirse, yukarıdakiler olacaktır:

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

Feragatname : {fmt} kütüphanesinin yazarıyım.


0

Tek astar olarak: name += std::to_string(age);


3
Bu, 0x499602D2 yanıtındaki kodla aynıdır.
BDL
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.