programing

C++ 문자열을 한 줄에 여러 개 연결하려면 어떻게 해야 합니까?

subpage 2023. 9. 16. 09:05
반응형

C++ 문자열을 한 줄에 여러 개 연결하려면 어떻게 해야 합니까?

C#에는 많은 데이터 유형을 한 줄에 연결할 수 있는 구문 기능이 있습니다.

string s = new String();
s += "Hello world, " + myInt + niceToSeeYouString;
s += someChar1 + interestingDecimal + someChar2;

C++에 해당하는 것은 무엇입니까?제가 보기에는 + 연산자로 여러 문자열/변수를 지원하지 않기 때문에 모든 작업을 별도의 라인에서 수행해야 할 것 같습니다.이것은 괜찮지만, 그렇게 단정해 보이지는 않습니다.

string s;
s += "Hello world, " + "nice to see you, " + "or not.";

위 코드에서 오류가 발생합니다.

#include <sstream>
#include <string>

std::stringstream ss;
ss << "Hello, world, " << myInt << niceToSeeYouString;
std::string s = ss.str();

Herb Sutter의 금주의 구루 기사를 보세요.장원농장의 현모양처

도 5살을 언급하지 ..append?

#include <string>

std::string s;
s.append("Hello world, ");
s.append("nice to see you, ");
s.append("or not.");
s += "Hello world, " + "nice to see you, " + "or not.";

문자 배열 리터럴은 C++ std:: 문자열이 아닙니다. 변환해야 합니다.

s += string("Hello world, ") + string("nice to see you, ") + string("or not.");

int(또는 다른 스트리밍 가능한 유형)를 변환하려면 boost lexical_cast를 사용하거나 고유한 기능을 제공할 수 있습니다.

template <typename T>
string Str( const T & t ) {
   ostringstream os;
   os << t;
   return os.str();
}

이제 다음과 같은 말을 할 수 있습니다.

string s = string("The meaning is ") + Str( 42 );

당신의1 코드는 다음과 같이 적을 수 있습니다.

s = "Hello world," "nice to see you," "or not."

...하지만 그게 당신이 찾던 것은 아닌 것 같네요.사용자의 경우 스트림을 찾고 있을 수 있습니다.

std::stringstream ss;
ss << "Hello world, " << 42 << "nice to see you.";
std::string s = ss.str();

1 "다음과 같이 있습니다" : 문자열 리터럴에만 적용됩니다.연결은 컴파일러에 의해 이루어집니다.

및 C++14 std::to_string코드가 쉬워집니다.

using namespace std::literals::string_literals;
std::string str;
str += "Hello World, "s + "nice to see you, "s + "or not"s;
str += "Hello World, "s + std::to_string(my_int) + other_string;

연결 문자열 리터럴은 컴파일 시간에 수행할 수 있습니다.다됩니다를 .+.

str += "Hello World, " "nice to see you, " "or not";

C++20에서 할 수 있는 일은 다음과 같습니다.

auto s = std::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);

std::format사용 가능합니다. {fmt} 라이브러리에서도 동일한 작업을 수행할 수 있습니다.

auto s = fmt::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);

면책 사항:저는 {fmt} and C++20의 저자입니다.std::format.

더 한 줄 같은 하려면: A 인 을 하기 하기 concat를 구현하여 "확장" 문자열 스트림 기반 솔루션을 하나의 문으로 줄일 수 있습니다.다양한 템플릿과 완벽한 전달을 기반으로 합니다.


용도:

std::string s = concat(someObject, " Hello, ", 42, " I concatenate", anyStreamableType);

구현:

void addToStream(std::ostringstream&)
{
}

template<typename T, typename... Args>
void addToStream(std::ostringstream& a_stream, T&& a_value, Args&&... a_args)
{
    a_stream << std::forward<T>(a_value);
    addToStream(a_stream, std::forward<Args>(a_args)...);
}

template<typename... Args>
std::string concat(Args&&... a_args)
{
    std::ostringstream s;
    addToStream(s, std::forward<Args>(a_args)...);
    return s.str();
}

부스트::형식

또는 std:: 문자열 스트림

std::stringstream msg;
msg << "Hello world, " << myInt  << niceToSeeYouString;
msg.str(); // returns std::string object

실제 문제는 문자열 리터럴을 연결하는 것이었습니다.+C++에서 실패:

string s;
s += "Hello world, " + "nice to see you, " + "or not.";
위 코드에서 오류가 발생합니다.

C++에서도 문자열 리터럴을 서로 바로 옆에 배치하여 연결합니다.

string s0 = "Hello world, " "nice to see you, " "or not.";
string s1 = "Hello world, " /*same*/ "nice to see you, " /*result*/ "or not.";
string s2 = 
    "Hello world, " /*line breaks in source code as well as*/ 
    "nice to see you, " /*comments don't matter*/ 
    "or not.";

매크로에서 코드를 생성하는 경우 이는 타당합니다.

#define TRACE(arg) cout << #arg ":" << (arg) << endl;

...이렇게 사용할 수 있는 간단한 매크로

int a = 5;
TRACE(a)
a += 7;
TRACE(a)
TRACE(a+7)
TRACE(17*11)

(라이브 데모...)

아니면, 당신이 사용하기를 고집한다면.+문자열 리터럴의 경우(undercore_d에서 이미 제시된 바와 같이):

string s = string("Hello world, ")+"nice to see you, "+"or not.";

은 문자열과 은 과 를 합니다 a 를 결합합니다.const char*

string s;
s += "Hello world, "
s += "nice to see you, "
s += "or not.";
auto s = string("one").append("two").append("three")

문자열에 집중할 모든 데이터 유형에 대해 operator+()를 정의해야 하지만 대부분의 유형에 대해 operator<<이 정의되므로 std::stringstream을 사용해야 합니다.

젠장, 50초 차이로...

만약 당신이 그것을 쓴다면.+= C#

string s("Some initial data. "); int i = 5;
s = s + "Hello world, " + "nice to see you, " + to_string(i) + "\n";

, 이 가 는 의 가 는 의 +음을 하지 않습니다.const char * 함께 합니다.std::string 예를 들어, 예를 들면.

에 C와 에 C++11 를 하는 이 을 사용하는 다른 솔루션이 for_each그리고 제공하는 것을 허용합니다.separator문자열을 분리하는 방법

#include <vector>
#include <algorithm>
#include <iterator>
#include <sstream>

string join(const string& separator,
            const vector<string>& strings)
{
    if (strings.empty())
        return "";

    if (strings.size() == 1)
        return strings[0];

    stringstream ss;
    ss << strings[0];

    auto aggregate = [&ss, &separator](const string& s) { ss << separator << s; };
    for_each(begin(strings) + 1, end(strings), aggregate);

    return ss.str();
}

용도:

std::vector<std::string> strings { "a", "b", "c" };
std::string joinedStrings = join(", ", strings);

적어도 컴퓨터에서 빠른 테스트를 한 후에는 (선형적으로) 확장이 잘 되는 것 같습니다. 다음은 제가 작성한 빠른 테스트입니다.

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <chrono>

using namespace std;

string join(const string& separator,
            const vector<string>& strings)
{
    if (strings.empty())
        return "";

    if (strings.size() == 1)
        return strings[0];

    stringstream ss;
    ss << strings[0];

    auto aggregate = [&ss, &separator](const string& s) { ss << separator << s; };
    for_each(begin(strings) + 1, end(strings), aggregate);

    return ss.str();
}

int main()
{
    const int reps = 1000;
    const string sep = ", ";
    auto generator = [](){return "abcde";};

    vector<string> strings10(10);
    generate(begin(strings10), end(strings10), generator);

    vector<string> strings100(100);
    generate(begin(strings100), end(strings100), generator);

    vector<string> strings1000(1000);
    generate(begin(strings1000), end(strings1000), generator);

    vector<string> strings10000(10000);
    generate(begin(strings10000), end(strings10000), generator);

    auto t1 = chrono::system_clock::now();
    for(int i = 0; i<reps; ++i)
    {
        join(sep, strings10);
    }

    auto t2 = chrono::system_clock::now();
    for(int i = 0; i<reps; ++i)
    {
        join(sep, strings100);
    }

    auto t3 = chrono::system_clock::now();
    for(int i = 0; i<reps; ++i)
    {
        join(sep, strings1000);
    }

    auto t4 = chrono::system_clock::now();
    for(int i = 0; i<reps; ++i)
    {
        join(sep, strings10000);
    }

    auto t5 = chrono::system_clock::now();

    auto d1 = chrono::duration_cast<chrono::milliseconds>(t2 - t1);
    auto d2 = chrono::duration_cast<chrono::milliseconds>(t3 - t2);
    auto d3 = chrono::duration_cast<chrono::milliseconds>(t4 - t3);
    auto d4 = chrono::duration_cast<chrono::milliseconds>(t5 - t4);

    cout << "join(10)   : " << d1.count() << endl;
    cout << "join(100)  : " << d2.count() << endl;
    cout << "join(1000) : " << d3.count() << endl;
    cout << "join(10000): " << d4.count() << endl;
}

결과(밀리초):

join(10)   : 2
join(100)  : 10
join(1000) : 91
join(10000): 898

다음은 원라이너 솔루션입니다.

#include <iostream>
#include <string>

int main() {
  std::string s = std::string("Hi") + " there" + " friends";
  std::cout << s << std::endl;

  std::string r = std::string("Magic number: ") + std::to_string(13) + "!";
  std::cout << r << std::endl;

  return 0;
}

약간 못생겼지만, 고양이가 C++에 들어가는 것만큼 깨끗하다고 생각합니다.

첫 번째 을 는 을 는 을 std::string로를다가다로(를)의 () 합니다.operator+그것의 왼쪽 피연산자가 항상 a임을 보장하기 위해.std::string. 는 합니다 으로 합니다 으로 는 을 연결합니다.std::string에와 const char *오른쪽 수술을 하고 다른 수술을 돌려주다std::string으로 표시,를 으로 으로 를

을 하여 에 은 과 과 은 을 하여 const char *,std::string,그리고.char.

매직넘버가 13인지 6227020800인지는 고객님의 판단에 달려있습니다.

제 "Streamer" 솔루션을 한 줄로 묶어서 사용하는 것이 좋을 수도 있습니다.

#include <iostream>
#include <sstream>
using namespace std;

class Streamer // class for one line string generation
{
public:

    Streamer& clear() // clear content
    {
        ss.str(""); // set to empty string
        ss.clear(); // clear error flags
        return *this;
    }

    template <typename T>
    friend Streamer& operator<<(Streamer& streamer,T str); // add to streamer

    string str() // get current string
    { return ss.str();}

private:
    stringstream ss;
};

template <typename T>
Streamer& operator<<(Streamer& streamer,T str)
{ streamer.ss<<str;return streamer;}

Streamer streamer; // make this a global variable


class MyTestClass // just a test class
{
public:
    MyTestClass() : data(0.12345){}
    friend ostream& operator<<(ostream& os,const MyTestClass& myClass);
private:
    double data;
};

ostream& operator<<(ostream& os,const MyTestClass& myClass) // print test class
{ return os<<myClass.data;}


int main()
{
    int i=0;
    string s1=(streamer.clear()<<"foo"<<"bar"<<"test").str();                      // test strings
    string s2=(streamer.clear()<<"i:"<<i++<<" "<<i++<<" "<<i++<<" "<<0.666).str(); // test numbers
    string s3=(streamer.clear()<<"test class:"<<MyTestClass()).str();              // test with test class
    cout<<"s1: '"<<s1<<"'"<<endl;
    cout<<"s2: '"<<s2<<"'"<<endl;
    cout<<"s3: '"<<s3<<"'"<<endl;
}

이와 관련하여 이 헤더를 사용할 수 있습니다: https://github.com/theypsilon/concat

using namespace concat;

assert(concat(1,2,3,4,5) == "12345");

후드 아래에는 std::ostringstream이 사용됩니다.

이 을 사용할 의향이 c++11당신은 사용자 정의 문자열 리터럴을 사용할 수 있고 a에 대해 더하기 연산자를 오버로드하는 두 함수 템플릿을 정의할 수 있습니다.std::string오브젝트 및 기타 오브젝트.은 ΔΔ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ ΔΔstd::string, 그렇지 않으면 컴파일러는 어떤 연산자를 사용할지 모릅니다.의 템플릿을 사용하여 이 작업을 수행할 수 있습니다. 이후 문자열은 Java 또는 C#에서와 같이 동작합니다.자세한 내용은 구현 예를 참조하십시오.

메인코드

#include <iostream>
#include "c_sharp_strings.hpp"

using namespace std;

int main()
{
    int i = 0;
    float f = 0.4;
    double d = 1.3e-2;
    string s;
    s += "Hello world, "_ + "nice to see you. "_ + i
            + " "_ + 47 + " "_ + f + ',' + d;
    cout << s << endl;
    return 0;
}

c_sharp_strings 파일입니다.흐흐흐

문자열을 가질 모든 위치에 이 헤더 파일을 포함합니다.

#ifndef C_SHARP_STRING_H_INCLUDED
#define C_SHARP_STRING_H_INCLUDED

#include <type_traits>
#include <string>

inline std::string operator "" _(const char a[], long unsigned int i)
{
    return std::string(a);
}

template<typename T> inline
typename std::enable_if<!std::is_same<std::string, T>::value &&
                        !std::is_same<char, T>::value &&
                        !std::is_same<const char*, T>::value, std::string>::type
operator+ (std::string s, T i)
{
    return s + std::to_string(i);
}

template<typename T> inline
typename std::enable_if<!std::is_same<std::string, T>::value &&
                        !std::is_same<char, T>::value &&
                        !std::is_same<const char*, T>::value, std::string>::type
operator+ (T i, std::string s)
{
    return std::to_string(i) + s;
}

#endif // C_SHARP_STRING_H_INCLUDED

이런 것들이 저한테 효과가 있어요.

namespace detail {
    void concat_impl(std::ostream&) { /* do nothing */ }

    template<typename T, typename ...Args>
    void concat_impl(std::ostream& os, const T& t, Args&&... args)
    {
        os << t;
        concat_impl(os, std::forward<Args>(args)...);
    }
} /* namespace detail */

template<typename ...Args>
std::string concat(Args&&... args)
{
    std::ostringstream os;
    detail::concat_impl(os, std::forward<Args>(args)...);
    return os.str();
}
// ...
std::string s{"Hello World, "};
s = concat(s, myInt, niceToSeeYouString, myChar, myFoo);

위의 솔루션들을 바탕으로 저는 제 프로젝트를 위해 var_string 클래스를 만들었습니다.예:

var_string x("abc %d %s", 123, "def");
std::string y = (std::string)x;
const char *z = x.c_str();

클래스 자체:

#include <stdlib.h>
#include <stdarg.h>

class var_string
{
public:
    var_string(const char *cmd, ...)
    {
        va_list args;
        va_start(args, cmd);
        vsnprintf(buffer, sizeof(buffer) - 1, cmd, args);
    }

    ~var_string() {}

    operator std::string()
    {
        return std::string(buffer);
    }

    operator char*()
    {
        return buffer;
    }

    const char *c_str()
    {
        return buffer;
    }

    int system()
    {
        return ::system(buffer);
    }
private:
    char buffer[4096];
};

C++에 더 좋은 것이 있을지 아직도 궁금하십니까?

Inc11:

void printMessage(std::string&& message) {
    std::cout << message << std::endl;
    return message;
}

이렇게 하면 다음과 같은 함수 호출을 만들 수 있습니다.

printMessage("message number : " + std::to_string(id));

will print : 메시지 번호 : 10

또한 문자열 클래스를 "선택"하고 원하는 연산자를 선택할 수 있습니다(<, &, | 등).

스트림과의 충돌이 없음을 보여주는 연산자<<를 사용한 코드입니다.

참고: 만약 당신이 s1.jp(30)에 대한 코멘트를 해제한다면, 오직 3개의 새로운 연산자 요청(s1에 대한 1개, s2에 대한 1개, 예비에 대한 1개; 유감스럽게도 당신은 컨스트럭터 시간에 예약할 수 없습니다)이 있습니다; 예비가 없다면, s1은 커짐에 따라 더 많은 메모리를 요청해야 하므로, 그것은 당신의 컴파일러 구현 증가율에 달려있습니다(이 예에서 나의 것은 1.5, 5개의 새로운 연산자 요청인 것 같습니다).

namespace perso {
class string:public std::string {
public:
    string(): std::string(){}

    template<typename T>
    string(const T v): std::string(v) {}

    template<typename T>
    string& operator<<(const T s){
        *this+=s;
        return *this;
    }
};
}

using namespace std;

int main()
{
    using string = perso::string;
    string s1, s2="she";
    //s1.reserve(30);
    s1 << "no " << "sunshine when " << s2 << '\'' << 's' << " gone";
    cout << "Aint't "<< s1 << " ..." <<  endl;

    return 0;
}

람다 함수를 사용하는 간단한 전처리기 매크로를 가진 문자열 스트림이 좋습니다.

#include <sstream>
#define make_string(args) []{std::stringstream ss; ss << args; return ss;}() 

그리고 나서.

auto str = make_string("hello" << " there" << 10 << '$');

이것은 저에게 효과가 있습니다.

#include <iostream>

using namespace std;

#define CONCAT2(a,b)     string(a)+string(b)
#define CONCAT3(a,b,c)   string(a)+string(b)+string(c)
#define CONCAT4(a,b,c,d) string(a)+string(b)+string(c)+string(d)

#define HOMEDIR "c:\\example"

int main()
{

    const char* filename = "myfile";

    string path = CONCAT4(HOMEDIR,"\\",filename,".txt");

    cout << path;
    return 0;
}

출력:

c:\example\myfile.txt

var = var + 를 사용하지 않고 +=?을(를) 피하려고 했습니까?그것은 나에게 효과가 있었다.

#include <iostream.h> // for string

string myName = "";
int _age = 30;
myName = myName + "Vincent" + "Thorpe" + 30 + " " + 2019;

언급URL : https://stackoverflow.com/questions/662918/how-do-i-concatenate-multiple-c-strings-on-one-line

반응형