[C++] 我如何在一行上連接多個C ++字符串?


Answers

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

那些字符數組文字不是C ++ std :: strings - 你需要轉換它們:

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

要轉換整數(或任何其他流式類型),您可以使用boost lexical_cast或提供自己的函數:

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

你現在可以這樣說:

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

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.";

上面的代碼產生一個錯誤。




如果你寫出+= ,它看起來幾乎與C#相同

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



正如其他人所說,OP代碼的主要問題是運算符+不會連接const char * ; 但它可以與std::string一起工作。

這是另一個使用C ++ 11 lambda和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






基於上述解決方案,我為我的項目製作了一個類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 ++中是否會有更好的東西?




為了提供更多單線的解決方案:可以實現函數concat以將“經典”基於stringstream的解決方案減少為單個語句 。 它基於可變模板和完美的轉發。

用法:

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



實際的問題是在C ++中使用+連接字符串文字失敗:

string s;
s += "Hello world, " + "nice to see you, " + "or not.";
上面的代碼產生一個錯誤。

在C ++中(也在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)

現場演示...

或者,如果你堅持使用+作為字符串文字(正如underscore_d建議的那樣):

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

另一個解決方案為每個級聯步驟組合了一個字符串和一個const char*

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



你的代碼可以寫成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可以寫成 ”:這只適用於字符串文字。 級聯由編譯器完成。




auto s = string("one").append("two").append("three")



有了{fmt}庫你可以做到:

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

該庫的一個子集被提議用於標準化為P0645文本格式 ,如果被接受,上述內容將變為:

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

免責聲明 :我是{fmt}圖書館的作者。