Single method string formatter

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












Because I don't want to download an entire library for a single function (which I do understand, was made better than I made mine), I decided to implement my own string formatting function.



I am not very proud of it, as I find it pretty ugly and unreadable.

This is only a string formatter with string-only arguments.

Efficiency is not a concern for me.



#include<iostream>
#include<unordered_map>
#include<string>

using std::string;
string formatString(string format, const std::unordered_map<string, string>& args)
string ret;

string::size_type bracketLoc;
while((bracketLoc = format.find_first_of('')) != string::npos)
// Handling the escape character.
if(bracketLoc > 0 && format[bracketLoc - 1] == '\')
ret += format.substr(0, bracketLoc + 1);
format = format.substr(bracketLoc + 1);
continue;


ret += format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

bracketLoc = format.find_first_of('');
string arg = format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

auto it = args.find(arg);
if(it == args.end())
ret += "(nil)";
else
ret += it->second;



ret += format;

return ret;


int main()
std::cout << formatString("Hello, Name! WeatherType weather, right?",
"Name", "Midnightas",
"Fruit", "Apple"
);

return 0;



Compile with -std=c++11.

The above program will output Hello, Midnightas! (nil) weather, right?.







share|improve this question





















  • No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
    – Incomputable
    May 26 at 16:36










  • Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
    – Midnightas
    May 26 at 16:40











  • I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
    – Reinderien
    May 26 at 16:58










  • @Reinderien I made this because the standard library doesn't support named arguments afaik.
    – Midnightas
    May 26 at 17:03











  • Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
    – Martin York
    May 26 at 17:25

















up vote
3
down vote

favorite












Because I don't want to download an entire library for a single function (which I do understand, was made better than I made mine), I decided to implement my own string formatting function.



I am not very proud of it, as I find it pretty ugly and unreadable.

This is only a string formatter with string-only arguments.

Efficiency is not a concern for me.



#include<iostream>
#include<unordered_map>
#include<string>

using std::string;
string formatString(string format, const std::unordered_map<string, string>& args)
string ret;

string::size_type bracketLoc;
while((bracketLoc = format.find_first_of('')) != string::npos)
// Handling the escape character.
if(bracketLoc > 0 && format[bracketLoc - 1] == '\')
ret += format.substr(0, bracketLoc + 1);
format = format.substr(bracketLoc + 1);
continue;


ret += format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

bracketLoc = format.find_first_of('');
string arg = format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

auto it = args.find(arg);
if(it == args.end())
ret += "(nil)";
else
ret += it->second;



ret += format;

return ret;


int main()
std::cout << formatString("Hello, Name! WeatherType weather, right?",
"Name", "Midnightas",
"Fruit", "Apple"
);

return 0;



Compile with -std=c++11.

The above program will output Hello, Midnightas! (nil) weather, right?.







share|improve this question





















  • No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
    – Incomputable
    May 26 at 16:36










  • Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
    – Midnightas
    May 26 at 16:40











  • I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
    – Reinderien
    May 26 at 16:58










  • @Reinderien I made this because the standard library doesn't support named arguments afaik.
    – Midnightas
    May 26 at 17:03











  • Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
    – Martin York
    May 26 at 17:25













up vote
3
down vote

favorite









up vote
3
down vote

favorite











Because I don't want to download an entire library for a single function (which I do understand, was made better than I made mine), I decided to implement my own string formatting function.



I am not very proud of it, as I find it pretty ugly and unreadable.

This is only a string formatter with string-only arguments.

Efficiency is not a concern for me.



#include<iostream>
#include<unordered_map>
#include<string>

using std::string;
string formatString(string format, const std::unordered_map<string, string>& args)
string ret;

string::size_type bracketLoc;
while((bracketLoc = format.find_first_of('')) != string::npos)
// Handling the escape character.
if(bracketLoc > 0 && format[bracketLoc - 1] == '\')
ret += format.substr(0, bracketLoc + 1);
format = format.substr(bracketLoc + 1);
continue;


ret += format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

bracketLoc = format.find_first_of('');
string arg = format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

auto it = args.find(arg);
if(it == args.end())
ret += "(nil)";
else
ret += it->second;



ret += format;

return ret;


int main()
std::cout << formatString("Hello, Name! WeatherType weather, right?",
"Name", "Midnightas",
"Fruit", "Apple"
);

return 0;



Compile with -std=c++11.

The above program will output Hello, Midnightas! (nil) weather, right?.







share|improve this question













Because I don't want to download an entire library for a single function (which I do understand, was made better than I made mine), I decided to implement my own string formatting function.



I am not very proud of it, as I find it pretty ugly and unreadable.

This is only a string formatter with string-only arguments.

Efficiency is not a concern for me.



#include<iostream>
#include<unordered_map>
#include<string>

using std::string;
string formatString(string format, const std::unordered_map<string, string>& args)
string ret;

string::size_type bracketLoc;
while((bracketLoc = format.find_first_of('')) != string::npos)
// Handling the escape character.
if(bracketLoc > 0 && format[bracketLoc - 1] == '\')
ret += format.substr(0, bracketLoc + 1);
format = format.substr(bracketLoc + 1);
continue;


ret += format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

bracketLoc = format.find_first_of('');
string arg = format.substr(0, bracketLoc);
format = format.substr(bracketLoc + 1);

auto it = args.find(arg);
if(it == args.end())
ret += "(nil)";
else
ret += it->second;



ret += format;

return ret;


int main()
std::cout << formatString("Hello, Name! WeatherType weather, right?",
"Name", "Midnightas",
"Fruit", "Apple"
);

return 0;



Compile with -std=c++11.

The above program will output Hello, Midnightas! (nil) weather, right?.









share|improve this question












share|improve this question




share|improve this question








edited May 26 at 16:20
























asked May 26 at 15:23









Midnightas

1185




1185











  • No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
    – Incomputable
    May 26 at 16:36










  • Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
    – Midnightas
    May 26 at 16:40











  • I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
    – Reinderien
    May 26 at 16:58










  • @Reinderien I made this because the standard library doesn't support named arguments afaik.
    – Midnightas
    May 26 at 17:03











  • Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
    – Martin York
    May 26 at 17:25

















  • No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
    – Incomputable
    May 26 at 16:36










  • Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
    – Midnightas
    May 26 at 16:40











  • I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
    – Reinderien
    May 26 at 16:58










  • @Reinderien I made this because the standard library doesn't support named arguments afaik.
    – Midnightas
    May 26 at 17:03











  • Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
    – Martin York
    May 26 at 17:25
















No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
– Incomputable
May 26 at 16:36




No worries, it started out fine, but now it's great. Please try to keep roughly the same format when you'll post new questions. On the more technical note, you might want to have a look at my answer to another post, as well as fmtlib, which seems to be on its way into standard.
– Incomputable
May 26 at 16:36












Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
– Midnightas
May 26 at 16:40





Yeah, that's the "entire library" that I meant, and I'm not really planning on using versions newer than C++11 as it's standard library does enough for me (Except for this).
– Midnightas
May 26 at 16:40













I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
– Reinderien
May 26 at 16:58




I don't understand how you arrived at the conclusion that the standard library can't do this. Maybe it's an issue of terminology. Maybe you mean to implement a string templating feature. Because both C and C++ can definitely already format strings.
– Reinderien
May 26 at 16:58












@Reinderien I made this because the standard library doesn't support named arguments afaik.
– Midnightas
May 26 at 17:03





@Reinderien I made this because the standard library doesn't support named arguments afaik.
– Midnightas
May 26 at 17:03













Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
– Martin York
May 26 at 17:25





Most libraries use positional rather than named overloads. ie "This is %2 of %1n", where %2 is replaced with the second argument and %1 is replaced with the first argument. Not sure if named arguments helps that much.
– Martin York
May 26 at 17:25











1 Answer
1






active

oldest

votes

















up vote
3
down vote



accepted










  1. You have a problem if you want to have the escape-character immediately before a replacement, because you don't support escaping the escape-character.

    I suggest dispensing with escape-characters, and simply replace an empty replacement with an opening brace {.


  2. There's no reason to modify the format-string at all, and thus receiving it by copy. Doing so is supremely inefficient. Well, using named arguments at all already is, so it might not matter too much.


  3. Do you know the ternary operator cond ? true_exp : false_exp? Using it would simplify things.



  4. Avoid allocations, thus avoid std::string. At least the format string should be C++17 std::string_view, maybe also the map should be too.

    If you template it, you don't even really have to decide for the caller:



    template <class Args = std::unordered_map<std::string_view, std::string_view>>
    std::string formatString(std::string_view format, const Args& args)






share|improve this answer





















  • Where would the ternary operator help here, other than when checking the existence of an argument?
    – Midnightas
    May 26 at 18:12











  • Just as you said, at the end of the loop when deciding what to add.
    – Deduplicator
    May 26 at 18:15










  • Some things I can't do here since I'm using C++11, but thanks!
    – Midnightas
    May 26 at 19:08










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195223%2fsingle-method-string-formatter%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted










  1. You have a problem if you want to have the escape-character immediately before a replacement, because you don't support escaping the escape-character.

    I suggest dispensing with escape-characters, and simply replace an empty replacement with an opening brace {.


  2. There's no reason to modify the format-string at all, and thus receiving it by copy. Doing so is supremely inefficient. Well, using named arguments at all already is, so it might not matter too much.


  3. Do you know the ternary operator cond ? true_exp : false_exp? Using it would simplify things.



  4. Avoid allocations, thus avoid std::string. At least the format string should be C++17 std::string_view, maybe also the map should be too.

    If you template it, you don't even really have to decide for the caller:



    template <class Args = std::unordered_map<std::string_view, std::string_view>>
    std::string formatString(std::string_view format, const Args& args)






share|improve this answer





















  • Where would the ternary operator help here, other than when checking the existence of an argument?
    – Midnightas
    May 26 at 18:12











  • Just as you said, at the end of the loop when deciding what to add.
    – Deduplicator
    May 26 at 18:15










  • Some things I can't do here since I'm using C++11, but thanks!
    – Midnightas
    May 26 at 19:08














up vote
3
down vote



accepted










  1. You have a problem if you want to have the escape-character immediately before a replacement, because you don't support escaping the escape-character.

    I suggest dispensing with escape-characters, and simply replace an empty replacement with an opening brace {.


  2. There's no reason to modify the format-string at all, and thus receiving it by copy. Doing so is supremely inefficient. Well, using named arguments at all already is, so it might not matter too much.


  3. Do you know the ternary operator cond ? true_exp : false_exp? Using it would simplify things.



  4. Avoid allocations, thus avoid std::string. At least the format string should be C++17 std::string_view, maybe also the map should be too.

    If you template it, you don't even really have to decide for the caller:



    template <class Args = std::unordered_map<std::string_view, std::string_view>>
    std::string formatString(std::string_view format, const Args& args)






share|improve this answer





















  • Where would the ternary operator help here, other than when checking the existence of an argument?
    – Midnightas
    May 26 at 18:12











  • Just as you said, at the end of the loop when deciding what to add.
    – Deduplicator
    May 26 at 18:15










  • Some things I can't do here since I'm using C++11, but thanks!
    – Midnightas
    May 26 at 19:08












up vote
3
down vote



accepted







up vote
3
down vote



accepted






  1. You have a problem if you want to have the escape-character immediately before a replacement, because you don't support escaping the escape-character.

    I suggest dispensing with escape-characters, and simply replace an empty replacement with an opening brace {.


  2. There's no reason to modify the format-string at all, and thus receiving it by copy. Doing so is supremely inefficient. Well, using named arguments at all already is, so it might not matter too much.


  3. Do you know the ternary operator cond ? true_exp : false_exp? Using it would simplify things.



  4. Avoid allocations, thus avoid std::string. At least the format string should be C++17 std::string_view, maybe also the map should be too.

    If you template it, you don't even really have to decide for the caller:



    template <class Args = std::unordered_map<std::string_view, std::string_view>>
    std::string formatString(std::string_view format, const Args& args)






share|improve this answer













  1. You have a problem if you want to have the escape-character immediately before a replacement, because you don't support escaping the escape-character.

    I suggest dispensing with escape-characters, and simply replace an empty replacement with an opening brace {.


  2. There's no reason to modify the format-string at all, and thus receiving it by copy. Doing so is supremely inefficient. Well, using named arguments at all already is, so it might not matter too much.


  3. Do you know the ternary operator cond ? true_exp : false_exp? Using it would simplify things.



  4. Avoid allocations, thus avoid std::string. At least the format string should be C++17 std::string_view, maybe also the map should be too.

    If you template it, you don't even really have to decide for the caller:



    template <class Args = std::unordered_map<std::string_view, std::string_view>>
    std::string formatString(std::string_view format, const Args& args)







share|improve this answer













share|improve this answer



share|improve this answer











answered May 26 at 17:50









Deduplicator

9,7511744




9,7511744











  • Where would the ternary operator help here, other than when checking the existence of an argument?
    – Midnightas
    May 26 at 18:12











  • Just as you said, at the end of the loop when deciding what to add.
    – Deduplicator
    May 26 at 18:15










  • Some things I can't do here since I'm using C++11, but thanks!
    – Midnightas
    May 26 at 19:08
















  • Where would the ternary operator help here, other than when checking the existence of an argument?
    – Midnightas
    May 26 at 18:12











  • Just as you said, at the end of the loop when deciding what to add.
    – Deduplicator
    May 26 at 18:15










  • Some things I can't do here since I'm using C++11, but thanks!
    – Midnightas
    May 26 at 19:08















Where would the ternary operator help here, other than when checking the existence of an argument?
– Midnightas
May 26 at 18:12





Where would the ternary operator help here, other than when checking the existence of an argument?
– Midnightas
May 26 at 18:12













Just as you said, at the end of the loop when deciding what to add.
– Deduplicator
May 26 at 18:15




Just as you said, at the end of the loop when deciding what to add.
– Deduplicator
May 26 at 18:15












Some things I can't do here since I'm using C++11, but thanks!
– Midnightas
May 26 at 19:08




Some things I can't do here since I'm using C++11, but thanks!
– Midnightas
May 26 at 19:08












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195223%2fsingle-method-string-formatter%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Python Lists

Aion

JavaScript Array Iteration Methods