Last active
June 6, 2020 13:30
-
-
Save LucaCorigliano/eb210a76b6e207b375c9281eba957222 to your computer and use it in GitHub Desktop.
Locale agnostic thousand separator adder for integer and decimal numbers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 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; | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* 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