Лучший способ добиться сложного числового форматирования в C # - PullRequest
3 голосов
/ 24 мая 2011

Каков наилучший способ повторить поведение чего-то подобного в C #?

// Converts decimal to a 0-padded string with minimum specified width and precision.
sprintf(out, "%0*.*lf", width, precision, decimal);

У меня было чтение стандартных , пользовательских и составных форматных строк, но я не вижу хорошего способа добиться этого.

Причина, по которой я спрашиваю, состоит в том, что я только что натолкнулся на этот уродливый фрагмент в каком-то коде, который я веду, где мы должны отформатировать группу десятичных знаков в соответствии с переменной шириной и точностью, как указано внешним интерфейсом:

private static String ZEROS = "00000000000000000000000000";

public override string Format(decimal input, int width, int precision)
{
    String formatString = ZEROS.Substring(0, width - precision - 1) 
                          + "." + ZEROS.Substring(0, precision);
    return ToDecimal(input).ToString(formatString);
}

и я хотел бы заменить его на нечто менее ужасное.

ОБНОВЛЕНИЕ

Поскольку окончательный ответ скрыт в комментариях, вот он:

public override string Format(decimal input, int width, int precision)
{
    string.Format("{0," + width + ":F" + precision + "}", input).Replace(" ","0");
}

В моем случае вход всегда положительный, так что это тоже работает:

public override string Format(decimal input, int width, int precision)
{
    return input.ToString("F"+precision).PadLeft(width, 0);
}

Ответы [ 5 ]

3 голосов
/ 24 мая 2011

Вы можете написать это так, сгенерировав строку стандартного формата и затем используя ее:

public static string Format(decimal input, int width, int precision)
{
    var format = string.Format("{{0,{0}:F{1}}}", width, precision);
    // generates (e.g. width=15, precision=5)  "{0,15:F5}"
    // then format using this and replace padding with zeroes
    return string.Format(format, input).Replace(" ", "0");
}

Или вместо того, чтобы дважды вызывать формат, просто объедините строку формата, в зависимости от ваших предпочтений:

string.Format("{0," + width + ":F" + precision + "}", input).Replace(" ","0")

Вы должны заменить пробелы после этого, так как нет способа указать символ заполнения. В качестве альтернативы вы можете написать свой собственный форматер для pad с определенным символом. Это работает, хотя:)

Редактировать: Это соответствует оригиналу для всех входов, кроме случаев, когда precision = 0. В этом случае оригинал неверен, поскольку он считает десятичную точку как часть ширины, даже если ее нет.

Упс: Забыл проверить отрицательные числа.

Вот более простая версия, но нужно проверить, является ли число отрицательным, чтобы получить правильное заполнение:

public override string Format(decimal input, int width, int precision)
{
    var output = input.ToString("F" + precision);
    return input < 0
        ? "-" + output.Substring(1).PadLeft(width, '0')
        :       output             .PadLeft(width, '0');
}
1 голос
/ 24 мая 2011

Примерно так:

return input.ToString(new string('0', width) + '.' + new string('0', precision));

?

Редактировать: на самом деле, вот лучше:

return input.ToString(new string('0', width - 1).insert(width - precision, '.'));
0 голосов
/ 24 мая 2011

Это примерно так же хорошо, как и получается:

public static string double2string( double value , int integerDigits , int fractionalDigits )
{
  string        decimalPoint = CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator ;
  StringBuilder sb           = new StringBuilder() ;

  sb.Append('0',integerDigits)
    .Append(decimalPoint)
    .Append('0',fractionalDigits)
    ;
  return value.ToString( sb.ToString() ) ;
}
0 голосов
/ 24 мая 2011

Полагаю, вы могли бы просто позвонить Decimal.ToString и передать ему строку произвольного числового формата , которую вы можете сгенерировать.

0 голосов
/ 24 мая 2011

Ну, один из способов избавиться от ZERO будет

public override string Format(decimal input, int width, int precision)
{
    String formatString = new string('0', width - precision - 1) 
                      + "." + new string('0', precision);
    return ToDecimal(input).ToString(formatString);
}

Не уверен, что вы можете сделать многое другое.

...