So a quick Google search didn't turn up anything useful in adding commas to numbers (like "1000") in standard C or C++ (preferably C++), so I wrote my own. Can I get some feedback on the attached source as to how I can/should do it better? I've also wrapped it in <code></code> tags below since it's so short.
Using std::stringstream is probably using a hammer to drive a thumbtack, but I've been having problems wrapping my mind around simpler solutions.
Untested, and probably some off-by-one errors:
Oh, and it's for positive numbers only.
Oh, and it's for positive numbers only.
Wouldn't it make sense, then, to change it to:
and save yourself the headache of the possibility of the negativity?
Here, now it should work fine:
That looks incredibly complicated for something this simple... can't you just do something like:
string format_with_commas(int number) { stringstream strs; strs << dec << number; string str = strs.str().reverse(); string result; for (size_t i = 0; i < str.length; ++i) { if (i && (i % 3 == 0)) { result = "," + result; } result += str[i]; } return result; }
I think locales are meant for that, although it seems very unportable. This compiles and prints the number with commas on Windows XP when compiled with VC 2005, but throws an exception with GCC.
However, with my native locale, it should use spaces as thousands separators, but it prints a with an accent mark instead.
Locales are an unknown territory to me but following some online tutorial and dinkumware's reference, I came up with this that can also format numbers in my locale.
Uh well without going in depth to the actual ideal solution, your use of stringstream is frustraitinly awful. Let me clean it up a bit.
There. That is a good (but untested) way to do it with stringstream. Also, there is a much quicker way to do something I saw in your code.
std::string result(ss.str()); unsigned num_chars = result.length();
You don't need a string to get the stream length! Use tellp which stands for "tell me the put pointer." The 'put pointer' is the character after the last one (aka. the size!)
unsigned num_chars = ss.tellp();
The second line below is pointless. A buffer starts out cleared!
std::stringstream ss; ss.str(""); // Clear the buffer
sigh
I guess I forgot that I've got to wrap my mind around an international market when I program anymore. I've always just grown up thinking that "192,168,100,100" was Bill Gates' annual salary and "192.168.100.100" was a local IP address. I keep forgetting that commas are different if I change locales.
Some of you are reusing the std::stringstream route... is there a reason that you're going that direction, like I had done? The first two posts by LennyLen and Matthew were mostly bare-bones, vanilla C implementations.
EDIT:
unsigned num_chars = ss.tellp();
I actually looked up tellp(), and tried it in a test case before posting my results here. I didn't use it here because when I used it in my test code, it returned a length of 0 in each case. Either I did something wrong, or I had input the data wrong somehow (it was right after the
line, and said that "value" gave a length of 0, while the string length gave an actual length. It was a kludge, but it worked).
The second line below is pointless. A buffer starts out cleared!
std::stringstream ss; ss.str(""); // Clear the buffer
Yeah, I know. That's actually because I use std::stringstream's a lot, and I am used to clearing the stream in this manner; it was left in more from habit than real necessity. Thanks for the spot, Dustin.
The first two posts by LennyLen and Matthew were mostly bare-bones, vanilla C implementations.
Because C fails at string manipulation (especially this one) while C++ owns at this particular string problem.
Because C fails at string manipulation (especially this one) while C++ owns at this particular string problem.
How about some C# then?
string FormatWithCommas(double value) { return value.ToString("#,#", CultureInfo.InvariantCulture)); }
Tobias, explain to me what's going on there.
I give you the number "1000" and it returns "1,000"? And "100000" returns "100,000" or "1000000000" correctly yields "1,000,000,000", and so forth?
No hidden strings attached?
It's part of .NET's string formatting routines. Here's the documentation. It's a bit counter-intuitive, but the format string "#,#" means format the number normally, and insert the applicable culture's thousands-separator where appropriate. The applicable culture (the .NET equivalent of a locale) is specified explicitly here as the "Invariant" culture, which more or less means the US-English culture; hence, the thousands-separator is the comma. If you specify a different culture instead, or leave it to .NET to decide for you (which means the local system's locale is generally selected unless the thread's culture has been changed somewhere else), the result may differ.
If you don't need to specify the culture for the particular statement, then the following is also equivalent:
return String.Format("{0:#,#}", value);
You can even use these in C++, but you'll have to use MSVC++ and managed C++, which is really an abomination.
Here's the same for Java (1.5+):
return String.format("%,d", integerValue); // Uses the system (default) locale // or return String.format(Locale.US, "%,d", integerValue); // Uses the specified locale, US here
(String.format is a convenience method for Formatter class.)
All C and C++ needs are people with experience in more modern frameworks to bring them up to speed. There's no reason that C# or Java code couldn't work in C++ too. It just hasn't been implemented by anyone, or at least not in a freely available and popular library... I'd love to see a rich standard library for both.