Skip to content

Instantly share code, notes, and snippets.

@LucaCorigliano
Last active June 6, 2020 13:30
Show Gist options
  • Select an option

  • Save LucaCorigliano/eb210a76b6e207b375c9281eba957222 to your computer and use it in GitHub Desktop.

Select an option

Save LucaCorigliano/eb210a76b6e207b375c9281eba957222 to your computer and use it in GitHub Desktop.
Locale agnostic thousand separator adder for integer and decimal numbers.
/*
Public domain, do whatever you want.
I wrote this snippet because I needed to add thousands separators to some numbers
and I wanted to avoid using locale-related code because:
- I wanted this code to be locale agnostic and always return the same result
- I didn't want to set the locale for the whole program just to do something like this
This is not meant to be fast and it can indeed be optimized. It's fine for my purposes.
*/
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <locale.h>
// Use whichever you want
#define THOUSAND_SEPARATOR '.'
// Use whichever you want. It will still try to use both . and , to identify the decimal point
#define DECIMAL_SEPARATOR ','
// This should not be called on it's own, but it's the core of the whole operation
std::string th_sep_str_work(std::string digits)
{
std::stringstream ss;
// Get the reverse end of this string (beginning)
auto rITend = digits.rend();
// If it's negative, we'll ignore the negative sign by shifting the beginning one place
bool negative = false;
if (digits[0] == '-') {
negative = true;
rITend--;
}
int i = 0;
// Iterate the number in reverse
for (auto rIT = digits.rbegin(); rIT < rITend; rIT++) {
// Append the digit
ss << *rIT;
// Every three digits we should add a point, except for the last one
if ((++i % 3) == 0 && i < (negative ? digits.length() - 1 : digits.length())) ss << THOUSAND_SEPARATOR;
}
// Re-add the minus sign if needed
if (negative)
ss << '-';
// Reverse and return the result
auto result = ss.str();
std::reverse(result.begin(), result.end());
return result;
}
// 123456789 -> 123.456.789
std::string th_sep_str(int val) {
// We'll just let th_sep_str_work do everything. We just transform it to a string
return th_sep_str_work(std::to_string(val));
}
// 123456789,012345-> 123.456.789,012345
std::string th_sep_str(float val, size_t maxDigits = 3) {
std::stringstream ss;
// Fetch the number as a string so we can process it
auto digits = std::to_string(val);
// Let's find the decimal point
size_t decimalPoint = digits.find(',');
if (decimalPoint == digits.npos) {
// Let's try again
decimalPoint = digits.find('.');
if ((decimalPoint) == digits.npos) {
// Maybe it's an integer? Let's proceed as such
return th_sep_str_work(digits);
}
}
// Safe to assume we have a decimal point here
auto integerPart = digits.substr(0, decimalPoint);
// If we don't have enough digits to process we'll just use what we have
size_t _maxDigits = min(maxDigits, digits.length() - decimalPoint);
auto decimalPart = digits.substr(decimalPoint + 1, maxDigits);
// Let's get the processed integer part
auto processedIntegerpart = th_sep_str_work(integerPart);
// And append the decimal part
return processedIntegerpart + DECIMAL_SEPARATOR + decimalPart;
}
/* Test */
int main(int argc, char **argv)
{
std::cout << th_sep_str(1) << std::endl;
std::cout << th_sep_str(12) << std::endl;
std::cout << th_sep_str(123) << std::endl;
std::cout << th_sep_str(1234) << std::endl;
std::cout << th_sep_str(12345) << std::endl;
std::cout << th_sep_str(123456) << std::endl;
std::cout << th_sep_str(1234567) << std::endl;
std::cout << th_sep_str(12345678) << std::endl;
std::cout << th_sep_str(123456789) << std::endl;
std::cout << th_sep_str(1234567890) << std::endl;
std::cout << th_sep_str(-1) << std::endl;
std::cout << th_sep_str(-12) << std::endl;
std::cout << th_sep_str(-123) << std::endl;
std::cout << th_sep_str(-1234) << std::endl;
std::cout << th_sep_str(-12345) << std::endl;
std::cout << th_sep_str(-123456) << std::endl;
std::cout << th_sep_str(-1234567) << std::endl;
std::cout << th_sep_str(-12345678) << std::endl;
std::cout << th_sep_str(-123456789) << std::endl;
std::cout << th_sep_str(-1234567890) << std::endl;
std::cout << th_sep_str(1.0f) << std::endl;
std::cout << th_sep_str(12.123f) << std::endl;
std::cout << th_sep_str(123.12453f, 400000) << std::endl;
std::cout << th_sep_str(1234.3123f) << std::endl;
std::cout << th_sep_str(12345.5496879f) << std::endl;
std::cout << th_sep_str(123456.6547f) << std::endl;
std::cout << th_sep_str(1234567.0f) << std::endl;
std::cout << th_sep_str(12345678.564f) << std::endl;
std::cout << th_sep_str(123456789.3f) << std::endl;
std::cout << th_sep_str(1234567890.164f) << std::endl;
std::cout << th_sep_str(-1.0f) << std::endl;
std::cout << th_sep_str(-12.123f) << std::endl;
std::cout << th_sep_str(-123.12453f) << std::endl;
std::cout << th_sep_str(-1234.3123f) << std::endl;
std::cout << th_sep_str(-12345.5496879f) << std::endl;
std::cout << th_sep_str(-123456.6547f) << std::endl;
std::cout << th_sep_str(-1234567.0f) << std::endl;
std::cout << th_sep_str(-12345678.564f) << std::endl;
std::cout << th_sep_str(-123456789.3f) << std::endl;
std::cout << th_sep_str(-1234567890.164f) << std::endl;
return 0;
}
/* Should return:
1
12
123
1.234
12.345
123.456
1.234.567
12.345.678
123.456.789
1.234.567.890
-1
-12
-123
-1.234
-12.345
-123.456
-1.234.567
-12.345.678
-123.456.789
-1.234.567.890
1,000
12,123
123,124527
1.234,312
12.345,549
123.456,656
1.234.567,000
12.345.679,000
123.456.792,000
1.234.567.936,000
-1,000
-12,123
-123,124
-1.234,312
-12.345,549
-123.456,656
-1.234.567,000
-12.345.679,000
-123.456.792,000
-1.234.567.936,000
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment