wxNumberFormatter::ToString
wxNumberFormatter::ToString
Hi there.
Is any way to format numbers using wxNumberFormatter::ToString for en_IN locale?
I have as a result that the group separators disappear. For other locales, everything is fine. PS I would not like to use regular expressions like this one: \B(?=(\d{2})+(\d)(?!\d)) , but if I have to, I do not understand how to get system information like the "Digit Grouping".
Is any way to format numbers using wxNumberFormatter::ToString for en_IN locale?
I have as a result that the group separators disappear. For other locales, everything is fine. PS I would not like to use regular expressions like this one: \B(?=(\d{2})+(\d)(?!\d)) , but if I have to, I do not understand how to get system information like the "Digit Grouping".
M$, VS2017, C++
Re: wxNumberFormatter::ToString
Hi,
Can you show some code?
Thank you.
Can you show some code?
Thank you.
Re: wxNumberFormatter::ToString
Just for the reference, there is this old unmerged PR:
https://github.com/wxWidgets/wxWidgets/pull/1781
https://github.com/wxWidgets/wxWidgets/pull/1781
Re: wxNumberFormatter::ToString
Code: Select all
int style = wxNumberFormatter::Style_WithThousandsSep;
wxString s = wxNumberFormatter::ToString(value, precision, style);
if (currency)
{
s.Replace(os_group_separator(), "\t");
s.Replace(wxNumberFormatter::GetDecimalSeparator(), "\x05");
s.Replace("\t", currency->GROUP_SEPARATOR);
s.Replace("\x05", currency->DECIMAL_POINT);
}
if (value >= -ROUNDING_ERROR_f32 && s.Mid(0, 1) == "-") {
s = s.Mid(1);
}
return s;
https://github.com/moneymanagerex/money ... #L187-L206
M$, VS2017, C++
Re: wxNumberFormatter::ToString
This piece of code returns me "3;0"
I expect a value "3;2;0" for the Indian locale. If it is this value, then I can apply my own formatting based on the regexp replace function.
Code: Select all
char buffer[255];
LCID lc = GetSystemDefaultLCID();
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING,
buffer, sizeof(buffer));
M$, VS2017, C++
Re: wxNumberFormatter::ToString
You must be doing something wrong, I would start with checking whether the locale is what you think it is and also the return codes of all functions.
When I set locale to en-IN on Win10 and run this
I get this
When I set locale to en-IN on Win10 and run this
Code: Select all
#include <wx/wx.h>
class MyApp : public wxApp
{
public:
bool OnInit() override
{
const LCID lcid = ::GetUserDefaultLCID();
WCHAR localeName[LOCALE_NAME_MAX_LENGTH]{0};
WCHAR numberGrouping[256]{0};
if ( !::GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) )
{
wxLogError("Could not retrieve the user default locale name.");
return false;
}
if ( !::GetLocaleInfoW(lcid, LOCALE_SGROUPING, numberGrouping, WXSIZEOF(numberGrouping)) )
{
wxLogError("Could not retrieve the number grouping.");
return false;
}
wxLogMessage("Locale name: %S\nNumber grouping: %S", localeName, numberGrouping);
return false;
}
}; wxIMPLEMENT_APP(MyApp);
Re: wxNumberFormatter::ToString
My problem that this code returns 123456.89 instead 1 23 456.89 in case if en_IN locale
Code: Select all
int style = wxNumberFormatter::Style_WithThousandsSep;
wxString s = wxNumberFormatter::ToString(123456.89, 2, style);
M$, VS2017, C++
Re: wxNumberFormatter::ToString
That is not your problem. That is a known wxWidgets issue, see the PR I linked in my first post in this thread.
I was referring to your previous post where you claimed your pure Win32 code unexpectedly returned "3;0" instead of "3;2;0".
I was referring to your previous post where you claimed your pure Win32 code unexpectedly returned "3;0" instead of "3;2;0".
Re: wxNumberFormatter::ToString
The code returned to me what is expected. My locale is not Indian. I'm trying to help an Indian guy.
Initially my question is:
Is any way to format numbers using wxNumberFormatter::ToString for en_IN locale?
Is there another way?
I wrote my own code, but I don't want to include it in the program for obvious reasons.
Code: Select all
static wxString gs;
if (gs.empty())
{
char buffer[255];
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING,
buffer, sizeof(buffer));
gs << buffer;
}
if (gs == "3;2;0" && fabs(value) >= 1000.00)
{
static std::map<int, wxString> gm;
if (gm.empty()) {
int g[] = { 13,11,9,7,5,3 };
for (int i = 0; i < 13; i++) {
auto *foo = std::find(std::begin(g), std::end(g), i);
gm[i] = foo != std::end(g) ? os_group_separator() : "";
}
}
wxString res;
wxString t = wxString::Format("%d", static_cast<int>(fabs(value)));
std::reverse(t.begin(), t.end());
for (int i = 0 ; i < t.length(); i++)
{
auto test = t[i];
res << gm[i] << t[i];
}
std::reverse(res.begin(), res.end());
t = res;
if (precision > 0) {
float j;
t << wxNumberFormatter::GetDecimalSeparator();
wxString dec = wxString::Format("00000000%d", static_cast<int>(modf(fabs(value), &j) * pow(10, precision)));
dec = dec.Mid(dec.length() - precision, precision);
t << dec;
}
if (value < ROUNDING_ERROR_f32)
t.Prepend("-");
s = t;
}
M$, VS2017, C++
Re: wxNumberFormatter::ToString
I hate to sound like a broken record, but for the third time: wxNumberFormatter does not use locale-specific number grouping, adding this feature was the topic of the unmerged pull request I linked in my very first post in this thread.
If you want number grouping, you are on your own for now. If you need MS WIndows only solution, you can look into FormatNumber() function. If you need something portable, perhaps look into C++ library, e.g. https://en.cppreference.com/w/cpp/local ... t/grouping
BTW, my locale is not Indian either. I just installed and set it to help a (Russian?) guy. ;)
If you want number grouping, you are on your own for now. If you need MS WIndows only solution, you can look into FormatNumber() function. If you need something portable, perhaps look into C++ library, e.g. https://en.cppreference.com/w/cpp/local ... t/grouping
BTW, my locale is not Indian either. I just installed and set it to help a (Russian?) guy. ;)
Re: wxNumberFormatter::ToString
It is obvious that wxNumberFormatter is not working as desired. The link you gave above is just a confirmation of this. Thank. You don't have to repeat it a hundred times.
Thank you for this information. This might come in handy.If you want number grouping, you are on your own for now. If you need MS WIndows only solution, you can look into FormatNumber() function. If you need something portable, perhaps look into C++ library, e.g. https://en.cppreference.com/w/cpp/local ... t/grouping
Yeah, thank you for your kind participation.BTW, my locale is not Indian either. I just installed and set it to help a (Russian?) guy.
M$, VS2017, C++
Re: wxNumberFormatter::ToString
There is an open source library called fmt that can most text formatting needs. Documentation is very good. It is compatible with the c++ STL, compile wxWidgets with STL compatibility turned on. You can use as header only, or compile it into a lib (I use static lib). It has many other useful features built in, such as printing the contents of standard containers which makes debugging so much faster!
When passing a string to fmt::format or related, use wxString::ToStdString() or implement a custom formatter.
https://fmt.dev/latest/api.html
Search "locale" on that page and you will find this example:
When passing a string to fmt::format or related, use wxString::ToStdString() or implement a custom formatter.
Code: Select all
fmt::format("String Value: {}", my_wxstring.ToStdString() );
Search "locale" on that page and you will find this example:
Code: Select all
#include <fmt/core.h>
#include <locale>
std::locale::global(std::locale("en_US.UTF-8"));
auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
Re: wxNumberFormatter::ToString
@rando thank you for your information.
Unfortunatly fmt lib has a bug.
https://github.com/fmtlib/fmt/issues/1392
However, I made a workaround code.
It remains only to remember how to get the value of the locale in this form: "en_IN".
Unfortunatly fmt lib has a bug.
https://github.com/fmtlib/fmt/issues/1392
However, I made a workaround code.
Code: Select all
int precision = 2;
wxString s = fmt::format(std::locale("en_IN"), "{:L}", static_cast<int>(value))
+
wxString(fmt::format("{:.{}f}"
, fabs(value - static_cast<int>(value))
, precision)).Mid(1);
M$, VS2017, C++