如何将百分比字符串转换为双倍?

时间:2010-01-31 12:16:14

标签: c# formatting

我有一个像“1.5%”的字符串,想要将其转换为double值。

可以通过以下方式完成:

public static double FromPercentageString(this string value)
{
    return double.Parse(value.SubString(0, value.Length - 1)) / 100;
}

但我不想使用这种解析方法。

是否有其他方法使用IFormatProvider或类似的东西?

10 个答案:

答案 0 :(得分:44)

文化敏感,请将其替换为:

  value = value.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");

然后解析它。

答案 1 :(得分:43)

如果你关心捕捉格式错误,我会使用TrimEnd而不是Replace。替换将允许格式错误未被检测到。

var num = decimal.Parse( value.TrimEnd( new char[] { '%', ' ' } ) ) / 100M;

这将确保该值必须是某个十进制数后跟任意数量的空格和百分号,即它必须至少以正确格式的值开头。更准确地说,您可能希望拆分'%',而不是删除空条目,然后确保只有两个结果,第二个是空的。第一个应该是要转换的值。

var pieces = value.Split( '%' );
if (pieces.Length > 2  || !string.IsNullOrEmpty(pieces[1]))
{ 
    ... some error handling ... 
}
var num = decimal.Parse( pieces[0] ) / 100M;

使用替换将允许您成功地,错误地IMO,解析如下内容:

  • %1.5
  • 1%0.5
  • 1%5

添加到1.5%

答案 2 :(得分:9)

只是略好一点,但不容易出错:

public static double FromPercentageString(this string value)
{
    return double.Parse(value.Replace("%","")) / 100;
}

答案 3 :(得分:8)

TypeConverter提供了将值类型转换为其他类型以及访问标准值和子属性的统一方法。 http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter%28VS.80%29.aspx

对于一次性转换,这可能有点过分。在ASP.NET或XAML中绑定属性或解析配置文件时,它更有用。

var result = new Percentage("1.5%");
double d = result.Value;

百分比及其TypeConverter定义为:

[TypeConverter(typeof(PercentageConverter))]
public struct Percentage
{
    public double Value;

    public Percentage( double value )
    {
        Value = value;
    }

    public Percentage( string value )
    {
        var pct = (Percentage) TypeDescriptor.GetConverter(GetType()).ConvertFromString(value);
        Value = pct.Value;
    }

    public override string ToString()
    {
        return ToString(CultureInfo.InvariantCulture);
    }

    public string ToString(CultureInfo Culture)
    {
        return TypeDescriptor.GetConverter(GetType()).ConvertToString(null, Culture, this);
    }
}

public class PercentageConverter : TypeConverter
{
    static TypeConverter conv = TypeDescriptor.GetConverter(typeof(double));

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return conv.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(Percentage)) {
            return true;
        }

        return conv.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value == null) {
            return new Percentage();
        }

        if (value is string) {
            string s = value as string;
            s = s.TrimEnd(' ', '\t', '\r', '\n');

            var percentage = s.EndsWith(culture.NumberFormat.PercentSymbol);
            if (percentage) {
                s = s.Substring(0, s.Length - culture.NumberFormat.PercentSymbol.Length);
            }

            double result = (double) conv.ConvertFromString(s);
            if (percentage) {
                result /= 100;
            }

            return new Percentage(result);
        }

        return new Percentage( (double) conv.ConvertFrom( context, culture, value ));
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (!(value is Percentage)) {
            throw new ArgumentNullException("value");
        }

        var pct = (Percentage) value;

        if (destinationType == typeof(string)) {
            return conv.ConvertTo( context, culture, pct.Value * 100, destinationType ) + culture.NumberFormat.PercentSymbol;
        }

        return conv.ConvertTo( context, culture, pct.Value, destinationType );
    }
}

答案 4 :(得分:6)

您还可以将前两个答案结合起来,以避免接受无效值,同时保持其对不同文化的灵活性。

var num = double.Parse(value.TrimEnd(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol.ToCharArray() ) ) / 100d;

答案 5 :(得分:6)

似乎这个问题的许多答案都涉及用空字符串替换文化的百分比符号,然后将结果字符串解析为数值。

也许我错过了一些东西,但这里仍有一些未处理的案例。具体而言,如果PercentDecimalSeparator与当前文化的NumberDecimalSeparator不同,会发生什么?如果PercentGroupSeparator与当前文化的NumberGroupSeparator不同,会发生什么?如果PercentGroupSizesNumberGroupSizes不同,会发生什么?

无论这种文化是否实际存在(如果它不存在,如果文化格式发生变化,将来很可能会出现),我认为可以更好地解决问题如果我们考虑这些额外的特殊情况,我们会发现。

这是一个代码段,显示其他答案(仅基于替换百分号)的情况将会失败,并建议如何更好地完成它:

        // Modify a culture so that it has different decimal separators and group separators for numbers and percentages.
        var customCulture = new CultureInfo("en-US")
            {
                NumberFormat = { PercentDecimalSeparator = "PDS", NumberDecimalSeparator = "NDS", PercentGroupSeparator = "PGS", NumberGroupSeparator = "NGS", PercentSymbol = "PS"}
            };
        // Set the current thread's culture to our custom culture
        Thread.CurrentThread.CurrentCulture = customCulture;
        // Create a percentage format string from a decimal value
        var percentStringCustomCulture = 123.45m.ToString("p");
        Console.WriteLine(percentStringCustomCulture); // renders "12PGS345PDS00 PS"
        // Now just replace the percent symbol only, and try to parse as a numeric value (as suggested in the other answers)
        var deceptiveNumericStringInCustomCulture = percentStringCustomCulture.Replace(customCulture.NumberFormat.PercentSymbol, string.Empty);
        // THE FOLLOWING LINE THROWS A FORMATEXCEPTION
        var decimalParsedFromDeceptiveNumericStringInCustomCulture = decimal.Parse(deceptiveNumericStringInCustomCulture); 

        // A better solution...replace the decimal separators and number group separators as well.
        var betterNumericStringInCustomCulture = deceptiveNumericStringInCustomCulture.Replace(customCulture.NumberFormat.PercentDecimalSeparator, customCulture.NumberFormat.NumberDecimalSeparator);
        // Here we mitigates issues potentially caused by group sizes by replacing the group separator by the empty string
        betterNumericStringInCustomCulture = betterNumericStringInCustomCulture.Replace(customCulture.NumberFormat.PercentGroupSeparator, string.Empty); 
        // The following parse then yields the correct result
        var decimalParsedFromBetterNumericStringInCustomCulture = decimal.Parse(betterNumericStringInCustomCulture)/100m;

是的,代码有点长,也许我是迂腐的(也许这样的文化永远不会存在)。也就是说,在我看来,这是一个更通用的解决方案。希望它能帮到某人:)。

答案 6 :(得分:4)

反思.NET 4,这是Microsoft的实现(在System.Windows.Documents.ZoomPercentageConverter.ConvertBack中找到)。您可以根据自己的需要进行修改。我总是在可能的情况下使用MS的实现!

        try
        {
            string str = (string) value;
            if ((culture != null) && !string.IsNullOrEmpty(str))
            {
                str = ((string) value).Trim();
                if ((!culture.IsNeutralCulture && (str.Length > 0)) && (culture.NumberFormat != null))
                {
                    switch (culture.NumberFormat.PercentPositivePattern)
                    {
                        case 0:
                        case 1:
                            if ((str.Length - 1) == str.LastIndexOf(culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase))
                            {
                                str = str.Substring(0, str.Length - 1);
                            }
                            break;

                        case 2:
                            if (str.IndexOf(culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase) == 0)
                            {
                                str = str.Substring(1);
                            }
                            break;
                    }
                }
                num = Convert.ToDouble(str, culture);
                flag = true;
            }
        }
        catch (ArgumentOutOfRangeException)
        {
        }
        catch (ArgumentNullException)
        {
        }
        catch (FormatException)
        {
        }
        catch (OverflowException)
        {
        }

答案 7 :(得分:4)

您可以在Microsoft Connect上投票支持此.NET Framework 4建议:Extend double.Parse to interpret Percent values

答案 8 :(得分:3)

我不确定所有这些字符串替换,替换和转换器是什么。

使用NumberFormat货币部分,但请填写所需文化中的百分比格式。



// input test value
string value = (.015m).ToString("P", CultureInfo.CurrentCulture);

// set up your format.
double doubleTest;
var numFormat = CultureInfo.CurrentCulture.NumberFormat;

NumberFormatInfo nfi = new NumberFormatInfo()
{
    CurrencyDecimalDigits = numFormat.PercentDecimalDigits,
    CurrencyDecimalSeparator = numFormat.PercentDecimalSeparator,
    CurrencyGroupSeparator = numFormat.PercentGroupSeparator,
    CurrencyGroupSizes = numFormat.PercentGroupSizes,
    CurrencyNegativePattern = numFormat.PercentNegativePattern,
    CurrencyPositivePattern = numFormat.PercentPositivePattern,
    CurrencySymbol = numFormat.PercentSymbol
};

// load it.
if (double.TryParse(value,  NumberStyles.Currency, nfi, out doubleTest))
{
    doubleTest /= 100D;
    // use as required.
}




答案 9 :(得分:-2)

这是一个字符串,无论你用它做什么来移除%符号,你仍然需要将它解析为双。