C # эквивалент imbue и numpunct

#c# #c

#c# #c

Вопрос:

Я пытаюсь найти эквивалент C # следующего в C . Это чисто для развлечения

 #include <iomanip>
#include <iostream>
#include <tchar.h>

class CommaSep : public std::numpunct<TCHAR>
{
public:
     CommaSep(TCHAR thousands_sep, const char* grouping)
        :m_thousands_sep(thousands_sep),
         m_grouping(grouping){}
protected:
     TCHAR do_thousands_sep() const{return m_thousands_sep;}
     std::string do_grouping() const {return m_grouping;}
private:
     TCHAR m_thousands_sep;
     std::string m_grouping;
};

int main()
{
    double number = 1234567.1235;
    std::locale comma_locale(std::locale(), new CommaSep(_T(','), "3"));
    std::locale indian_locale(std::locale(), new CommaSep(_T(','), "223"));
    std::locale weird_locale(std::locale(), new CommaSep(_T(','), "213"));

    std::wcout.imbue(comma_locale);
    std::wcout << std::setprecision(2) << std::fixed << number << std::endl;
    std::wcout.imbue(indian_locale);
    std::wcout << std::setprecision(2) << std::fixed << number << std::endl;
    std::wcout.imbue(weird_locale);
    std::wcout << std::setprecision(2) << std::fixed << number << std::endl;
}
  

В результате получается

 1,234,567.12
123,45,67.12
1,234,5,67.12
  

Он делает именно то, что я ему говорю. Я попробовал следующее в C #. Код намного меньше (ура), но компилятор просто игнорирует форматирование и делает свое дело (шипение)

 namespace imbuecs
{
    class Imbue
    {
        static void Main(string[] args)
        {
            int bignum = 123456789;

            System.Console.WriteLine(bignum.ToString("########0"));
            // Indian
            System.Console.WriteLine(bignum.ToString("##,###,##,#0"));
            System.Console.WriteLine(bignum.ToString("###,###,##0"));
            // Chinese
            System.Console.WriteLine(bignum.ToString("#,####,###0"));
        }
    }
}
  

То, что я получил, было

 123456789
123,456,789  expected 12,345,67,89
123,456,789
123,456,789  expected 1,2345,6789
  

Я могу написать огромные участки кода для этого, но мне интересно, есть ли простой способ сделать это.

Комментарии:

1. «намного меньше» — вы могли бы написать совершенно неправильный код и на C , и он тоже был бы короче 🙂 .. Если вам действительно важно, вы должны использовать соответствующее CultureInfo форматирование, зависящее от локали, а не какое-то ручное решение.

2. CultureInfo не будет использовать странный язык, для чего я обычно его использую. Иногда мне приходится отображать разделители в нестандартных позициях.

Ответ №1:

Из документации, при указании пользовательского форматирования, запятая (курсив мой):

Служит как разделителем групп, так и спецификатором масштабирования чисел. В качестве разделителя групп он вставляет локализованный символ разделителя групп между каждой группой. В качестве спецификатора масштабирования чисел он делит число на 1000 для каждой указанной запятой.

Таким образом, это приводит к тому, что число группируется в 3 цифры. Если вы хотите создать свой собственный формат, вам нужно заключить запятую в одинарные кавычки, чтобы отобразить ее как буквальную строку. Например:

 Console.WriteLine(bignum.ToString("##','###','##','#0"));
Console.WriteLine(bignum.ToString("#','####','###0"));
  

Будет выводить:

 12,345,67,89
1,2345,6789
  

Другой альтернативой является использование NumberFormatInfo объекта со свойством NumberGroupSizes . Например:

 var nfi = new System.Globalization.NumberFormatInfo();
//First group is 2 digits, the rest are 3 digits
nfi.NumberGroupSizes = new int[] { 2, 3 }; 

Console.WriteLine(bignum.ToString("#,#0", nfi));