JavaScript has a number formatter (part of the Internationalization API).
// Create our number formatter.
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
// These options are needed to round to whole numbers if that's what you want.
//minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
//maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
});
formatter.format(2500); /* $2,500.00 */
Use undefined
in place of the first argument ('en-US'
in the example) to use the system locale (the user locale in case the code is running in a browser). Further explanation of the locale code.
Here's a list of the currency codes.
Intl.NumberFormat vs Number.prototype.toLocaleString
A final note comparing this to the older .toLocaleString
. They both offer essentially the same functionality. However, toLocaleString in its older incarnations (pre-Intl) does not actually support locales: it uses the system locale. So when debugging old browsers, be sure that you're using the correct version (MDN suggests to check for the existence of Intl
). There isn't any need to worry about this at all if you don't care about old browsers or just use the shim.
Also, the performance of both is the same for a single item, but if you have a lot of numbers to format, using Intl.NumberFormat
is ~70 times faster. Therefore, it's usually best to use Intl.NumberFormat
and instantiate only once per page load. Anyway, here's the equivalent usage of toLocaleString
:
(2500).toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
}); /* $2,500.00 */
Some notes on browser support and Node.js
- Browser support is no longer an issue nowadays with 98% support globally, 99% in the US and 99+% in the EU
- There is a shim to support it on fossilized browsers (like Internet Explorer 8), should you really need to
- Node.js before v13 only supports
en-US
out of the box. One solution is to install full-icu, see here for more information
- Have a look at CanIUse for more information
EDIT Since c++17, some parts of the standard library were removed. Fortunately, starting with c++11, we have lambdas which are a superior solution.
#include <algorithm>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
Thanks to https://stackoverflow.com/a/44973498/524503 for bringing up the modern solution.
Original answer:
I tend to use one of these 3 for my trimming needs:
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start
static inline std::string <rim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
// trim from end
static inline std::string &rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
// trim from both ends
static inline std::string &trim(std::string &s) {
return ltrim(rtrim(s));
}
They are fairly self-explanatory and work very well.
EDIT: BTW, I have std::ptr_fun
in there to help disambiguate std::isspace
because there is actually a second definition which supports locales. This could have been a cast just the same, but I tend to like this better.
EDIT: To address some comments about accepting a parameter by reference, modifying and returning it. I Agree. An implementation that I would likely prefer would be two sets of functions, one for in place and one which makes a copy. A better set of examples would be:
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
I am keeping the original answer above though for context and in the interest of keeping the high voted answer still available.
Best Solution
Don't store it just as cents, since you'll accumulate errors when multiplying for taxes and interest pretty quickly. At the very least, keep an extra two significant digits: $12.45 would be stored as 124,500. If you keep it in a signed 32 bit integer, you'll have $200,000 to work with (positive or negative). If you need bigger numbers or more precision, a signed 64 bit integer will likely give you all the space you'll need for a long time.
It might be of some help to wrap this value in a class, to give you one place for creating these values, doing arithmetic on them, and formatting them for display. This would also give you a central place to carry around which currency it being stored (USD, CAD, EURO, etc).