2010-01-31 165 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

相關問題