├── .gitignore ├── Format.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | -------------------------------------------------------------------------------- /Format.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace util 12 | { 13 | class ArgBase 14 | { 15 | public: 16 | ArgBase() {} 17 | virtual ~ArgBase() {} 18 | virtual void Format(std::ostringstream &ss, const std::string& fmt) = 0; 19 | }; 20 | 21 | template 22 | class Arg : public ArgBase 23 | { 24 | public: 25 | Arg(T arg) : m_arg(arg) {} 26 | virtual ~Arg(){} 27 | virtual void Format(std::ostringstream &ss, const std::string& fmt) 28 | { 29 | ss << m_arg; 30 | } 31 | private: 32 | T m_arg; 33 | }; 34 | 35 | class ArgArray : public std::vector < ArgBase* > 36 | { 37 | public: 38 | ArgArray() {} 39 | ~ArgArray() 40 | { 41 | std::for_each(begin(), end(), [](ArgBase* p){ delete p; }); 42 | } 43 | }; 44 | 45 | static void FormatItem(std::ostringstream& ss, const std::string& item, const ArgArray& args) 46 | { 47 | int index = 0; 48 | int alignment = 0; 49 | std::string fmt; 50 | 51 | char* endptr = nullptr; 52 | index = strtol(&item[0], &endptr, 10); 53 | if (index < 0 || index >= args.size()) 54 | { 55 | return; 56 | } 57 | 58 | if (*endptr == ',') 59 | { 60 | alignment = strtol(endptr + 1, &endptr, 10); 61 | if (alignment > 0) 62 | { 63 | ss << std::right << std::setw(alignment); 64 | } 65 | else if (alignment < 0) 66 | { 67 | ss << std::left << std::setw(-alignment); 68 | } 69 | } 70 | 71 | if (*endptr == ':') 72 | { 73 | fmt = endptr + 1; 74 | } 75 | 76 | args[index]->Format(ss, fmt); 77 | 78 | return; 79 | } 80 | 81 | template 82 | static void Transfer(ArgArray& argArray, T t) 83 | { 84 | argArray.push_back(new Arg(t)); 85 | } 86 | 87 | template 88 | static void Transfer(ArgArray& argArray, T t, Args&&... args) 89 | { 90 | Transfer(argArray, t); 91 | Transfer(argArray, args...); 92 | } 93 | 94 | template 95 | std::string Format(const std::string& format, Args&&... args) 96 | { 97 | if (sizeof...(args) == 0) 98 | { 99 | return format; 100 | } 101 | 102 | ArgArray argArray; 103 | Transfer(argArray, args...); 104 | size_t start = 0; 105 | size_t pos = 0; 106 | std::ostringstream ss; 107 | while (true) 108 | { 109 | pos = format.find('{', start); 110 | if (pos == std::string::npos) 111 | { 112 | ss << format.substr(start); 113 | break; 114 | } 115 | 116 | ss << format.substr(start, pos - start); 117 | if (format[pos + 1] == '{') 118 | { 119 | ss << '{'; 120 | start = pos + 2; 121 | continue; 122 | } 123 | 124 | start = pos + 1; 125 | pos = format.find('}', start); 126 | if (pos == std::string::npos) 127 | { 128 | ss << format.substr(start - 1); 129 | break; 130 | } 131 | 132 | FormatItem(ss, format.substr(start, pos - start), argArray); 133 | start = pos + 1; 134 | } 135 | 136 | return ss.str(); 137 | } 138 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | format 2 | ====== 3 | 4 | A simple header-only C++11 std::string formatter 5 | 6 | Usage: 7 | ------ 8 | 9 | ```c++ 10 | 11 | std::string test = util::Format("This is a nice string with numbers {0} and strings {1} nicely formatted", 123, "hello"); 12 | std::string test = util::Format("{0, 20}", "Formatting is nice!"); 13 | ``` 14 | --------------------------------------------------------------------------------