2010-01-31 159 views
24

我有一个像“1.5%”的字符串,并且想将它转换为double值。如何将百分比字符串转换为双精度?

这是可以做到的简单与以下:

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

,但我不希望使用此方法解析。

IFormatProvider还有其他的方法吗?

回答

38

如果您关心捕获格式错误,我会使用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%。5
  • 1%5

另外还有1.5%

+0

你可以使用'if(value.EndsWith(“%”))...' – Bitterblue 2014-03-31 12:34:34

+1

有些文化以百分比开始,所以你真的需要CultureInfo.CurrentCulture.NumberFormat – 2016-01-06 13:43:53

-1

这是一个字符串,无论你如何去除%符号,都必须将其解析为双精度。

+2

这不是一个问题的答案-1。 – 2010-01-31 12:38:39

+0

@ C.Ross,实际上它是一个答案,它是正确的答案,如果你实际上很烦恼地阅读这个问题,你会发现他并不“想要使用这种解析方法”,事实上,除了Convert.ToDouble之外唯一可以等价的方法。 – 2010-01-31 12:53:12

+0

据我所知,OP指的是他在他的帖子中所用的_particular_解析方法。意思是括号之间的位 - 不是解析方法的实际使用。即使你考虑你的贡献,不幸的是我发现它并不是非常有用(-1)。我建议你不要用“不管你用它来删除%符号”来做什么,而是用不同的选项来展开如何处理%符号。这是OP问题的症结所在,也是我在此页面结束的原因。这也有助于其他来这里寻找答案的人。 – Ben 2013-08-10 10:25:47

9

仅略好,但不易出错:

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

这是文化的敏感,这样的替换:

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

然后解析它。

+0

+1非常简单的解决方案 – 2012-09-04 19:03:09

+0

我认为这里有(技术上)未处理的案例。看到我的答案。 – sammy34 2014-05-24 07:03:38

+1

将此用作字符串的扩展方法:public static string RemovePercentageSign(this string str) return str.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol,string.Empty); } – 2015-07-09 11:48:01

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(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

+1。恕我直言,这是这个问题的最佳答案。除了您的代码之外,在转换为基本类型时,我还会为较不详细的使用者代码添加两个隐式转换运算符。一个用于String(静态公共隐式运算符String(百分比pct){返回pct.ToString();}')和其他用于Decimal,因为我已经更改了原始样本以使用十进制来获得更好的精度('static public implicit operator小数(百分比pct){return pct._value;}')。 – 2010-11-01 21:37:42

4

反映到.NET 4中,这里是微软实现(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) 
     { 
     } 
+0

提及WPF的“ZoomPercentageConverter”+1。这将显着帮助那些在WPF场景中参与此问答的人员,他们只需使用内置的转换器,而无需编写任何新代码。 – 2015-06-22 22:15:24

5

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

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

似乎很多这个问题的答案涉及与空字符串替换文化的百分比符号,然后解析生成的字符串作为一个数值。

也许我错过了一些东西,但这里仍然有一些未处理的情况。具体而言,如果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; 

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

+0

太棒了!它可以帮助我很多。平均时间我很惊讶MS证明了decimal.ToString(“P2”);为什么他们不提供decimal.ParseExact(“P2”,stringValue)。 – 2015-10-21 16:30:33

+0

如果你想考虑各种文化,这是最好的。备注:“10 %%”是什么意思?根据你的代码,它等于0.1,但也可以说这意味着(10%)%,等于0.001。建议:只删除第一个百分号并递归调用函数。但是,这并不考虑PercentPositivePattern和PercentNegativePattern,因此如果您有一个来自不同文化的百分比模式组合的数字,您仍然会生成一个数字,如同它是有效的:“%-10%” – 2016-01-06 13:50:51

1

我不确定它是什么与所有此字符串替换,替换和转换器。

使用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. 
 
}

+1

您必须划分通过100. – 2016-12-30 01:37:57

+0

@ErwinMayer我已经添加了更正。 – midspace 2016-12-31 11:08:52

相关问题