C# StringFormat 처럼 짜려다가 가변인자 타입 자체를 확인을 못함.
어쩔수 없이 출력 형식로 확인
code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Common
사용법
자리수까지 구현은 했으나 별로...
printf("%s",Common::String::Format("%lf %s", 10.0, "test").c_str());
※ 장점은 출력 형식을 내맘대로 정할수 있다는 점이지만 vsnprintf로 구현하는게 속 편할듯
NS.h
#pragma once
#ifndef COMMON_H
#define COMMON_H
#define NS_COMMON_BEGIN namespace Common {
#define NS_COMMON_END }
#define USING_COMMON using namespace Common;
#endif
StringFormat.h
#pragma once
#include <string>
#include <stdarg.h>
#include <map>
#include "NS.h"
NS_COMMON_BEGIN
class String
{
private:
class FormatEmun
{
private:
friend class String;
private:
enum class Signature
{
None,
d, //int
u, //unsigned int
f, //float
c, //char
s, //char*
wc, //wchar
ws, //wchar_t*
lf, //double
ld, //long
lld //long long
};
std::map<std::string, Signature> _enumMap;
public:
FormatEmun()
{
_enumMap = {
{ "d", Signature::d },
{ "u", Signature::u },
{ "f", Signature::f },
{ "c", Signature::c },
{ "s", Signature::s },
{ "wc", Signature::wc },
{ "ws", Signature::ws },
{ "lf", Signature::lf },
{ "ld", Signature::ld },
{ "lld", Signature::lld }
};
}
virtual ~FormatEmun()
{
_enumMap.clear();
}
private:
Signature Find(std::string signature);
Signature Find(std::wstring signature);
};
public:
static std::wstring String::Format(std::wstring format, ...);
static std::string String::Format(std::string format, ...);
private:
template<typename T, typename Traits, typename Alloc>
static std::basic_string<T, Traits, Alloc> Format(std::basic_string<T, Traits, Alloc> format, va_list& args);
template<typename T, typename Traits, typename Alloc>
static std::basic_string<T, Traits, Alloc> FillDigit(std::basic_string<T, Traits, Alloc>& arg, std::basic_string<T, Traits, Alloc>& digit);
};
inline String::FormatEmun::Signature String::FormatEmun::Find(std::string signature)
{
auto it = _enumMap.find(signature);
if (it != _enumMap.end())
return it->second;
else
return Signature::None;
}
inline String::FormatEmun::Signature String::FormatEmun::Find(std::wstring signature)
{
std::string _signature(signature.begin(), signature.end());
return Find(_signature);
}
NS_COMMON_END
StringFormat.cpp
#include "StringFormat.h"
#include <typeinfo>
NS_COMMON_BEGIN
template<typename T, typename Traits, typename Alloc>
std::basic_string<T, Traits, Alloc> String::Format(std::basic_string<T, Traits, Alloc> format, va_list& args)
{
FormatEmun formatEnum;
std::basic_string<T, Traits, Alloc> output;
for (size_t i = 0; i < format.size(); i++)
{
if (format[i] != '%')
{
output.push_back(format[i]);
}
else if (format[i] == '%')
{
std::basic_string<T, Traits, Alloc> key;
std::basic_string<T, Traits, Alloc> digit;
i++;
bool find = false;
while (i<format.size())
{
if (format[i] >= '0' && format[i] <= '9' || format[i] == '.')
digit.push_back(format[i]);
else
key.push_back(format[i]);
auto type = formatEnum.Find(key);
if (type != FormatEmun::Signature::None)
{
find = true;
switch (type)
{
case FormatEmun::Signature::d:
{
auto arg = va_arg(args, int);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
case FormatEmun::Signature::u:
{
auto arg = va_arg(args, unsigned int);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
case FormatEmun::Signature::f:
{
auto arg = va_arg(args, double);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
case FormatEmun::Signature::c:
{
auto arg = va_arg(args, char);
output.push_back(arg);
break;
}
case FormatEmun::Signature::s:
{
auto arg = va_arg(args, char*);
std::string str(arg);
output.append(str.begin(), str.end());
break;
}
case FormatEmun::Signature::wc:
{
auto arg = va_arg(args, wchar_t);
std::wstring wstr;
wstr.push_back(arg);
output.append(wstr.begin(), wstr.end());
break;
}
case FormatEmun::Signature::ws:
{
auto arg = va_arg(args, wchar_t*);
std::wstring wstr(arg);
output.append(wstr.begin(), wstr.end());
break;
}
case FormatEmun::Signature::lf:
{
auto arg = va_arg(args, double);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
case FormatEmun::Signature::ld:
{
auto arg = va_arg(args, long);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
case FormatEmun::Signature::lld:
{
auto arg = va_arg(args, long long);
if (typeid(T) == typeid(char))
{
auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
else if (typeid(T) == typeid(wchar_t))
{
auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));
output.append(fill.begin(), fill.end());
}
break;
}
}
break;
}
i++;
}
if (!find)
output.append(key);
}
}
return output;
}
std::string String::Format(std::string format, ...)
{
FormatEmun formatEnum;
va_list args;
try
{
va_start(args, format);
std::string output;
output = Format<char, std::char_traits<char>, std::allocator<char>>(format, args);
va_end(args);
return output;
}
catch (std::exception ex)
{
va_end(args);
throw ex;
}
}
std::wstring String::Format(std::wstring format, ...)
{
FormatEmun formatEnum;
va_list args;
try
{
std::wstring output;
va_start(args, format);
output = Format<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(format, args);
va_end(args);
return output;
}
catch (std::exception ex)
{
va_end(args);
throw ex;
}
}
template<typename T, typename Traits, typename Alloc>
static std::basic_string<T, Traits, Alloc> String::FillDigit(std::basic_string<T, Traits, Alloc>& arg, std::basic_string<T, Traits, Alloc>& digit)
{
if (digit.empty()) return arg;
std::basic_string<T, Traits, Alloc> output;
std::basic_string<T, Traits, Alloc> find_key;
find_key.push_back('.');
int idx = digit.find(find_key);
if (idx == -1)
{
auto size = std::stoi(digit) - arg.size();
for (unsigned int i = 0; i < size; i++)
{
output.push_back(' ');
}
output.append(arg);
}
else
{
auto decimalDigit = digit.substr(idx + 1, digit.size() - idx + 1);
auto argDigit = arg.find(find_key);
if (argDigit != -1)
output.append(arg.substr(0, argDigit));
else
output.append(arg);
if (!decimalDigit.empty())
{
std::basic_string<T, Traits, Alloc> argDecimal;
output.push_back('.');
if (argDigit != -1)
{
argDecimal = arg.substr(argDigit + 1, arg.size() - argDigit);
output.append(argDecimal.begin(), argDecimal.end());
}
size_t size = std::stoi(decimalDigit);
if (size > argDecimal.size())
{
for (size_t i = 0; i < size - argDecimal.size(); i++)
{
output.push_back('0');
}
}
else if (size != 0)
{
for (size_t i = 0; i < size; i++)
{
output.push_back(argDecimal[i]);
}
}
else
{
output.pop_back();
}
}
auto integerDigit = digit.substr(0, idx);
if (!integerDigit.empty())
{
auto size = std::stoi(integerDigit) - output.size();
for (unsigned int i = 0; i < size; i++)
{
output.insert(output.begin(), ' ');
}
}
}
return output;
}
NS_COMMON_END
'개발관련 > C&C++' 카테고리의 다른 글
Functional 이용한 델리게이트 (0) | 2018.04.26 |
---|---|
IOCP Socket Server 구현 (0) | 2018.04.16 |
라이브러리 빌드 전/후 이벤트 명령어 (0) | 2018.03.16 |
C#처럼 이벤트 처리 (0) | 2018.02.27 |
Convert Json To Xml (0) | 2018.01.17 |