格式化double值以适合最大字符串大小

时间:2013-12-05 15:09:18

标签: c# string-formatting

我需要格式化一个double值,使其适合13个字符的字段。有没有办法用String.Format执行此操作,还是我坚持逐个字符的工作?

编辑:(希望他们这次会留下来)

如果案件超过一万亿,我就会报告错误。它基本上是一个计算器界面。

我自己的回答:

private void DisplayValue(double a_value)
{
    String displayText = String.Format("{0:0." + "".PadRight(_maxLength, '#') + "}", a_value);

    if (displayText.Length > _maxLength)
    {
        var decimalIndex = displayText.IndexOf('.');
        if (decimalIndex >= _maxLength || decimalIndex < 0)
        {
            Error();
            return;
        }

        var match = Regex.Match(displayText, @"^-?(?<digits>\d*)\.\d*$");
        if (!match.Success)
        {
            Error();
            return;
        }

        var extra = 1;
        if (a_value < 0)
            extra = 2;

        var digitsLength = match.Groups["digits"].Value.Length;
        var places = (_maxLength - extra) - digitsLength;

        a_value = Math.Round(a_value, places);

        displayText = String.Format("{0:0." + "".PadRight(_maxLength, '#') + "}", a_value);

        if (displayText.Length > _maxLength)
        {
            Error();
            return;
        }
    }

    DisplayText = displayText;
}

3 个答案:

答案 0 :(得分:2)

如果这是计算器,那么你不能使用你在问题中提到的逐字符方法。您必须先将数字舍入到所需的小数位,然后才显示它,否则您可能会得到错误的结果。例如,修剪为长度4的数字1.99999将是1.99,但结果2将更正确。

以下代码将满足您的需求:

int maxLength = 3;
double number = 1.96;
string output = null;
int decimalPlaces = maxLength - 2; //because every decimal contains at least "0."
bool isError = true;

while (isError && decimalPlaces >= 0)
{
    output = Math.Round(number, decimalPlaces).ToString();
    isError = output.Length > maxLength;
    decimalPlaces--;
}

if (isError)
{
    //handle error
}
else
{
    //we got result
    Debug.Write(output);
}

答案 1 :(得分:0)

使用String.Format有很多格式化选项,只需在占位符之后指定格式,如{0:format}。

完整示例如下所示:

Console.WriteLine("Your account balance is {0:N2}.", value);

输出将是:

Your account balance is 15.34.

此处列出了数字类型的所有选项:

http://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx

答案 2 :(得分:0)

这似乎对我有用(但是是手工制作的):

    static string FormatDouble(double d)
    {
        int maxLen = 13;
        double threshold = Math.Pow(10, maxLen);

        if (d >= threshold || d <= 0 - (threshold/10))
            return "OVERFLOW";
        string strDisplay = "" + d;
        if (strDisplay.Length > maxLen )
            strDisplay = strDisplay.Substring(0, maxLen);
        if (strDisplay.EndsWith("."))
            strDisplay = strDisplay.Replace(".", "");
        return strDisplay;
    }

让我知道它是否会让你在科学记法中遇到麻烦。我相信格式"{0:R}"可以帮助你明确地避免这种情况。

此外,我不确定您是否包含+/-登录数字计数,或者是否在单独的UI插槽中。

这里关于四舍五入的理论是,是的,"" + d可以围绕一些事情,但总的来说,它将比以往显示的数字更多,所以它应该无关紧要。所以这个方法应该总是截断。

这是一个四舍五入的解决方案。 (我想不出一种非数学方法):

    static string FormatDouble(double d)
    {
        int maxLen = 13;
        int places = (int)Math.Max(Math.Log10(Math.Abs(d)), 0);
        places += (d == Math.Abs(d) ? 1 : 2);
        if (places > maxLen || places < 1 - maxLen)
            return "OVERFLOW";
        if (Math.Floor(d) == d) ++places;  // no decimal means one extra spot 
        d = Math.Round(d, Math.Max(maxLen - places - 1, 0));
        return string.Format("{0:R}", d);
    }

注意:我仍然认为您的用户可能会喜欢看到更接近存储在底层内存中的内容,而不是典型的计算器。 (我特别讨厌可以将0.99变成1.01的那种)无论哪种方式,你现在至少有3个解决方案,所以这取决于你。