C++용 문자열.형식
-
19-08-2019 - |
문제
.NET의 String.Format과 같은 함수의 C++ 구현을 찾고 있습니다.분명히 printf가 있고 다양한 종류가 있지만 다음과 같이 위치에 따른 것을 찾고 있습니다.
String.Format("안녕하세요 {0}.당신은 {1} 나이입니다.{1}? ", 이름, 나이)라고 느끼는 느낌;
이는 앱 현지화를 더 쉽게 만들고 번역자에게 문장의 아무 위치에나 {0} 및 {1}을 제공하는 것이 %s, %d, %를 제공하는 것보다 훨씬 쉽기 때문에 필요합니다. d는 번역 시 해당 순서로 배치되어야 합니다.
검색하고 변수 입력(va_start, va_end 등)으로 바꾸는 것이 결국 구축이 될 것이라고 생각하지만 이미 확실한 솔루션이 있다면 그것이 더 바람직할 것입니다.
감사해요 :)
해결책 6
대부분의 상황에서 작동하는 위의 많은 좋은 권장 사항. 제 경우에는 궁극적으로 리소스에서 문자열을로드하고 문자열 자원을 .net String.format에 가깝게 유지하여 내 자신을 굴 렸습니다. 아이디어를 위해 위의 일부 구현을 살펴본 후 결과 구현은 매우 짧고 쉽습니다.
내 경우에는 Microsoft의 CSTRING에서 파생되는 클래스 문자열이 있지만 모든 문자열 클래스에서 파생 될 수 있습니다. Class StringArg도 있습니다. 직무는 매개 변수 유형을 가져 와서 문자열로 바꾸는 것입니다 (예 : .NET의 ToString을 모방). 새 객체를 tostring'd 해야하는 경우 다른 생성자를 추가합니다. 생성자는 비 디펜트 형식에 대한 printf 스타일 형식 지정자를 허용합니다.
그런 다음 문자열 클래스는 소스 문자열에 대한 문자열 테이블 ID, 다수의 StringArg 매개 변수 및 마지막으로 선택적인 Hinstance를 수락합니다 (많은 DLL을 사용하고 문자열 테이블을 호스팅 할 수 있으므로 전달할 수 있습니다. 또는 기본적으로 DLL- 특이 적 hinstance를 사용하십시오).
사용 예제 :
dlg.m_prompt = String(1417); //"Welcome to Stackoverflow!"
MessageBox(String(1532, m_username)); //"Hi {0}"
그대로 입력에 대한 문자열 ID 만 사용하지만 문자열 ID 대신 입력 문자열을 추가하는 것은 사소한 일입니다.
CString s = String.Format("Hi {0}, you are {1} years old in Hexidecimal", m_userName, StringArg(m_age, "%0X"));
이제 변수에 대한 토스트 링에 해당하는 StringArg 클래스의 경우 :
class StringArg
{
StringArg(); //not implemented
StringArg(const StringArg&); //not implemented
StringArg& operator=(const StringArg&); //not implemented
public:
StringArg(LPCWSTR val);
StringArg(const CString& val);
StringArg(int val, LPCWSTR formatSpec = NULL);
StringArg(size_t val, LPCWSTR formatSpec = NULL);
StringArg(WORD val, LPCWSTR formatSpec = NULL);
StringArg(DWORD val, LPCWSTR formatSpec = NULL);
StringArg(__int64 val, LPCWSTR formatSpec = NULL);
StringArg(double val, LPCWSTR formatSpec = NULL);
CString ToString() const;
private:
CString m_strVal;
};
extern HINSTANCE GetModuleHInst(); //every DLL implements this for getting it's own HINSTANCE -- scenarios with a single resource DLL wouldn't need this
문자열 클래스의 경우 최대 10 개의 인수를 취하는 멤버 기능과 생성자가 많이 있습니다. 이것들은 궁극적으로 실제 작업을 수행하는 CentralFormat이라고 부릅니다.
class String : public CString
{
public:
String() { }
String(WORD stringTableID, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, hInst); }
String(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, hInst); }
String(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst = GetModuleHInst()) { Format(stringTableID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, hInst); }
CString& Format(WORD stringTableID, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst = GetModuleHInst());
CString& Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst = GetModuleHInst());
private:
void CentralFormat(WORD stringTableID, std::vector<const StringArg*>& args, HINSTANCE hInst);
};
마지막으로, 구현 (stackoverflow에 이것을 많이 게시해도 괜찮습니다. 대부분의 대량은 매우 간단합니다).
StringArg::StringArg(LPCWSTR val)
{
m_strVal = val;
}
StringArg::StringArg(const CString& val)
{
m_strVal = (LPCWSTR)val;
}
StringArg::StringArg(int val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%d"; //GLOK
m_strVal.Format(formatSpec, val);
}
StringArg::StringArg(size_t val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%u"; //GLOK
m_strVal.Format(formatSpec, val);
}
StringArg::StringArg(WORD val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%u"; //GLOK
m_strVal.Format(formatSpec, val);
}
StringArg::StringArg(DWORD val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%u"; //GLOK
m_strVal.Format(formatSpec, val);
}
StringArg::StringArg(__int64 val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%I64d"; //GLOK
m_strVal.Format(formatSpec, val);
}
StringArg::StringArg(double val, LPCWSTR formatSpec)
{
if(NULL == formatSpec)
formatSpec = L"%f"; //GLOK
m_strVal.Format(formatSpec, val);
}
CString StringArg::ToString() const
{
return m_strVal;
}
void String::CentralFormat(WORD stringTableID, std::vector<const StringArg*>& args, HINSTANCE hInst)
{
size_t argsCount = args.size();
_ASSERT(argsCount < 10); //code below assumes a single character position indicator
CString tmp;
HINSTANCE hOld = AfxGetResourceHandle();
AfxSetResourceHandle(hInst);
BOOL b = tmp.LoadString(stringTableID);
AfxSetResourceHandle(hOld);
if(FALSE == b)
{
#ifdef _DEBUG
//missing string resource, or more likely a bad stringID was used -- tell someone!!
CString s;
s.Format(L"StringID %d could not be found! %s", stringTableID, hInst == ghCommonHInst ? L"CommonHInst was passed in" : L"CommonHInst was NOT passed in"); //GLOK
::MessageBeep(MB_ICONHAND);
::MessageBeep(MB_ICONEXCLAMATION);
::MessageBeep(MB_ICONHAND);
_ASSERT(0);
::MessageBox(NULL, s, L"DEBUG Error - Inform Development", MB_ICONSTOP | MB_OK | MB_SERVICE_NOTIFICATION); //GLOK
}
#endif //_DEBUG
CString::Format(L"(???+%d)", stringTableID); //GLOK
return;
}
//check for the degenerate case
if(0 == argsCount)
{
CString::operator=(tmp);
return;
}
GetBuffer(tmp.GetLength() * 3); //pre-allocate space
ReleaseBuffer(0);
LPCWSTR pStr = tmp;
while(L'\0' != *pStr)
{
bool bSkip = false;
if(L'{' == *pStr)
{
//is this an incoming string position?
//we only support 10 args, so the next char must be a number
if(wcschr(L"0123456789", *(pStr + 1))) //GLOK
{
if(L'}' == *(pStr + 2)) //and closing brace?
{
bSkip = true;
//this is a replacement
size_t index = *(pStr + 1) - L'0';
_ASSERT(index < argsCount);
_ASSERT(index >= 0);
if((index >= 0) && (index < argsCount))
CString::operator+=(args[index]->ToString());
else
{
//bad positional index
CString msg;
msg.Format(L"(??-%d)", index); //GLOK
CString::operator+=(msg);
}
pStr += 2; //get past the two extra characters that we skipped ahead and peeked at
}
}
}
if(false == bSkip)
CString::operator+=(*pStr);
pStr++;
}
}
CString& String::Format(WORD stringTableID, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
args.push_back(&arg5);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
args.push_back(&arg5);
args.push_back(&arg6);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
args.push_back(&arg5);
args.push_back(&arg6);
args.push_back(&arg7);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
args.push_back(&arg5);
args.push_back(&arg6);
args.push_back(&arg7);
args.push_back(&arg8);
CentralFormat(stringTableID, args, hInst);
return *this;
}
CString& String::Format(WORD stringTableID, const StringArg& arg1, const StringArg& arg2, const StringArg& arg3, const StringArg& arg4, const StringArg& arg5, const StringArg& arg6, const StringArg& arg7, const StringArg& arg8, const StringArg& arg9, HINSTANCE hInst)
{
std::vector<const StringArg*> args;
args.push_back(&arg1);
args.push_back(&arg2);
args.push_back(&arg3);
args.push_back(&arg4);
args.push_back(&arg5);
args.push_back(&arg6);
args.push_back(&arg7);
args.push_back(&arg8);
args.push_back(&arg9);
CentralFormat(stringTableID, args, hInst);
return *this;
}
다른 팁
를보세요 형식 라이브러리 부스트.
QT의 QString은 다음을 수행 할 수 있습니다.
QString("Hi there %1. You are %2 years old. How does it feel \
to be %2?").arg(name).arg(age)
믿거 나 말거나, printf와 친구들은 위치 주장을지지합니다.
#include <stdio.h>
int main() {
char *name = "Logan";
int age = 25;
printf("Hi there %1$s, you are %2$d years old. How does it feel to be %2$d?\n", name, age);
return 0;
}
당신은 FastFormat-도서관.
나는 당신이 사용할 수 있다고 생각합니다 FastFormat, 처럼
std::string result;
fastformat::fmt(result, "Hi there {0}. You are {1} years old. How does it feel to be {1}?", name, age);
거의 동일한 구문입니다.
몇 가지 옵션 :
- 형식 라이브러리 부스트 (이미 언급)
- 문자열
- 레거시 printf/sprintf 함수
- 일반 표현식 또는 내장 문자열 함수를 사용한 사용자 정의 구현
관련 메모에서, 당신이 말하는 것은 현지화에 완전히 부적절합니다.
ioStream :
stringstream s;
string a;
s << "this is string a: " << a << endl;
Sprintf ( "ioStream 형식"의 Google)와 C ++ 표준에서 형식을 형식화 할 수 있습니다.
직접 작성하려는 경우 검색 및 바꾸기는 아마도 최선의 접근 방식이 아닐 것입니다. 대부분의 검색/바꾸기 방법에서는 한 번에 하나씩만 바꿀 수 있고 Escpae 문자를 허용하는 작업이 매우 형편없기 때문입니다(예: 리터럴 문자열을 포함하고 싶습니다 {0}
귀하의 출력에.
입력 문자열을 살펴보고 한 번에 즉석에서 출력 문자열을 생성하는 유한 상태 시스템을 직접 작성하는 것이 훨씬 더 좋습니다.이를 통해 이스케이프 문자와 더 복잡한 출력 기능(예: 현지화된 날짜)을 처리할 수 있습니다. {0:dd\MM\yyyy}
예를 들어).검색/바꾸기 또는 정규식 접근 방식보다 더 빠르며 더 많은 유연성을 제공합니다.
Windows 타겟팅? formatmessage () 당신의 친구입니다
크로스 플랫폼이어야한다면 Boost :: 형식 또는 ICU에 투표합니다. Windows 만 지원 해야하는 경우 FormatMessage (또는 MFC를 사용하는 경우 Cstring :: FormatMessage의 편리한 래퍼)
비교를 위해 여기서 살펴볼 수 있습니다. http://www.mihai-nita.net/article.php?artid=20060430a
얼마 전, 나는 그런 일을하려고했지만 몇 가지 추가 가정을 가지고있었습니다.
- 위치 형식에 대한 지원 없음 (그래서 나는 당신을 위해 갈 수 없다고 생각합니다)
- C ++ 2K3 (일부 이전 코드와 함께 통합 할 수 있도록)
- (거의) 의존성 없음 (CRT조차도 SPRINTF 종속성 없음)
나는 그것에 실패했고 완전히 미완성되었지만 여전히 몇 가지 결과를 볼 수 있습니다.
http://code.google.com/p/pileofcrap/source/browse/tests_format.cpp
http://code.google.com/p/pileofcrap/source/browse/format/format.h
다른 사람들이 제안한 옵션 외에도 추천 할 수 있습니다. FMT 라이브러리 문자열 서식을 구현합니다 str.format
파이썬에서 String.Format
C#에서. 예는 다음과 같습니다.
string result = fmt::format("Hi {0}. You are {1} years old.", name, age);
라이브러리는 완전히 안전합니다 훨씬 더 빨리 부스트 형식보다.
면책 조항 : 저는이 도서관의 저자입니다.