한 줄에 여러 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 : Manor Farm의 String Formatters 의이 Guru Of The Week 기사를 살펴보십시오.
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 :: strings가 아닙니다. 변환해야합니다.
s += string("Hello world, ") + string("nice to see you, ") + string("or not.");
int (또는 다른 스트리밍 가능한 유형)를 변환하려면 lexical_cast를 사용하거나 고유 한 기능을 제공 할 수 있습니다.
template <typename T>
string Str( const T & t ) {
ostringstream os;
os << t;
return os.str();
}
이제 다음과 같이 말할 수 있습니다.
string s = "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";
보다 한 줄짜리 솔루션을 제공하려면 : 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 :: stringstream
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 ++ (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)
( 실시간 데모 ... )
또는 +
for 문자열 리터럴을 사용해야한다고 주장하는 경우 ( 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.";
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} 라이브러리의 저자입니다.
문자열에 적용하려는 모든 데이터 유형에 대해 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";
다른 사람들이 말했듯이 OP 코드의 주요 문제점은 운영자 +
가 연결하지 않는다는 것입니다 const char *
. std::string
그래도 작동합니다 .
다음은 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 <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
할 수 있습니다 . 유일한 함정은의 더하기 연산자를 오버로드 하지 않는 것 입니다 . 그렇지 않으면 컴파일러는 사용할 연산자를 모릅니다. 의 템플릿 을 사용하여이 작업을 수행 할 수 있습니다 . 그 후에 문자열은 Java 또는 C #에서와 같이 동작합니다. 자세한 내용은 예제 구현을 참조하십시오.std::string
std::string
std::enable_if
type_traits
메인 코드
#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.hpp
이 문자열을 갖고 싶은 모든 곳에이 헤더 파일을 포함 시키십시오.
#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
문자열 클래스를 "확장"하고 원하는 연산자를 선택할 수도 있습니다 (<<, &, | 등 ...).
다음은 스트림과 충돌이 없음을 보여주기 위해 operator <<를 사용하는 코드입니다.
참고 : s1.reserve (30)의 주석 처리를 제거하면 3 개의 new () 연산자 요청 만 있습니다 (s1의 경우 1, s2의 경우 1, 예약의 경우 1; 불행히도 생성자 시간에 예약 할 수 없음). 예비가 없으면 s1은 증가함에 따라 더 많은 메모리를 요청해야하므로 컴파일러 구현 증가 요인에 따라 다릅니다 (이 예제에서는 광산이 1.5, 5 new () 호출 인 것 같습니다)
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;
}
이 같은 것이 나를 위해 작동
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 ++에서 더 좋은 것이 있는지 궁금합니다.
c11에서 :
void printMessage(std::string&& message) {
std::cout << message << std::endl;
return message;
}
이를 통해 다음과 같이 함수 호출을 작성할 수 있습니다.
printMessage("message number : " + std::to_string(id));
인쇄합니다 : 메시지 번호 : 10
한 줄짜리 솔루션은 다음과 같습니다.
#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 ++에서 얻는 것처럼 깨끗하다고 생각합니다.
첫 번째 인수를 a로 캐스팅 std::string
한 다음 왼쪽 피연산자가 항상 a operator+
인지 확인 하기 위해 (왼쪽에서 오른쪽으로) 평가 순서 를 사용합니다 . 이런 식으로 왼쪽에있는 피연산자를 오른쪽에있는 피연산자 와 연결하고 다른 피연산자를 반환 하여 효과를 계단식으로 만듭니다.std::string
std::string
const char *
std::string
참고 :이 포함 우측 피연산자에 대한 몇 가지 옵션이 있습니다 const char *
, std::string
하고 char
.
매직 넘버가 13인지 6227020800인지를 결정하는 것은 당신에게 달려 있습니다.
람다 함수를 사용하는 간단한 선행 작업 매크로가있는 문자열 스트림은 멋지게 보입니다.
#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
'development' 카테고리의 다른 글
Android 에뮬레이터 : 설치 오류 : INSTALL_FAILED_VERSION_DOWNGRADE (0) | 2020.06.25 |
---|---|
항상 관리자 모드로 실행되도록 BAT 파일을 코딩하는 방법은 무엇입니까? (0) | 2020.06.25 |
PHP에서 서 수가 붙은 숫자 표시 (0) | 2020.06.25 |
moment.js로 문자열을 파싱 (0) | 2020.06.25 |
Android Studio의 OpenCV (0) | 2020.06.25 |