C# 如何将百分比字符串转换为双倍?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2171615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert percentage string to double?
提问by sashaeve
I have a string like "1.5%" and want to convert it to double value.
我有一个像“1.5%”这样的字符串,想把它转换成双精度值。
It can be done simple with following:
可以通过以下方式简单地完成:
public static double FromPercentageString(this string value)
{
return double.Parse(value.SubString(0, value.Length - 1)) / 100;
}
but I don't want to use this parsing approach.
但我不想使用这种解析方法。
Is any other approach with IFormatProvider or something like this?
IFormatProvider 是否还有其他方法或类似的方法?
采纳答案by tvanfosson
If you care about catching formatting errors, I would use TrimEnd rather than Replace. Replace would allow formatting errors to pass undetected.
如果您关心捕获格式错误,我会使用 TrimEnd 而不是 Replace。替换将允许格式错误未被检测到。
var num = decimal.Parse( value.TrimEnd( new char[] { '%', ' ' } ) ) / 100M;
This will ensure that the value must be some decimal number followed by any number of spaces and percent signs, i.e, it must at least start with a value in the proper format. To be more precise you might want to split on '%', not removing empty entries, then make sure that there are only two results and the second is empty. The first should be the value to convert.
这将确保该值必须是某个十进制数后跟任意数量的空格和百分号,即它必须至少以正确格式的值开头。更准确地说,您可能希望在 '%' 上拆分,而不是删除空条目,然后确保只有两个结果并且第二个结果为空。第一个应该是要转换的值。
var pieces = value.Split( '%' );
if (pieces.Length > 2 || !string.IsNullOrEmpty(pieces[1]))
{
... some error handling ...
}
var num = decimal.Parse( pieces[0] ) / 100M;
Using Replace will allow you to successfully, and wrongfully IMO, parse things like:
使用 Replace 将允许您成功且错误地 IMO 解析以下内容:
- %1.5
- 1%.5
- 1.%5
- %1.5
- 1%.5
- 1.%5
in addtion to 1.5%
除了 1.5%
回答by Paul Creasey
It's a string, no matter what you do with it to remove the % sign you still have to parse it to a double.
它是一个字符串,无论您用它做什么来删除 % 符号,您仍然必须将其解析为双精度值。
回答by Nick Craver
Only slightly better, but less error-prone:
只是稍微好一点,但不太容易出错:
public static double FromPercentageString(this string value)
{
return double.Parse(value.Replace("%","")) / 100;
}
回答by Hans Passant
It is culture sensitive, replace it like this:
它是文化敏感的,像这样替换它:
value = value.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
Then parse it.
然后解析它。
回答by Lachlan Roche
TypeConverter provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties. http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter%28VS.80%29.aspx
TypeConverter 提供了一种将值的类型转换为其他类型以及访问标准值和子属性的统一方法。http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter%28VS.80%29.aspx
This is probably overkill for one-off conversions. It is far more useful when binding properties in ASP.NET or XAML, or when parsing config files.
对于一次性转换来说,这可能是矫枉过正。在 ASP.NET 或 XAML 中绑定属性时,或者在解析配置文件时,它更有用。
var result = new Percentage("1.5%");
double d = result.Value;
Percentage and its TypeConverter are defined as:
Percentage 及其 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 );
}
}
回答by Matt
Reflecting into .NET 4, here is Microsoft's implementation (found in System.Windows.Documents.ZoomPercentageConverter.ConvertBack). You can modify this to suit your needs. I alway's use MS's implementation when possible!
反映到 .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)
{
}
回答by jbe
You might vote for this .NET Framework 4 suggestion on Microsoft Connect: Extend double.Parse to interpret Percent values
您可能会投票支持 Microsoft Connect 上的 .NET Framework 4 建议:Extend double.Parse to interpret Percent values
回答by Robb Vandaveer
You could also combine the top two answers to avoid accepting invalid values while keeping it flexible for different cultures.
您还可以结合前两个答案以避免接受无效值,同时保持它对不同文化的灵活性。
var num = double.Parse(value.TrimEnd(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol.ToCharArray() ) ) / 100d;
回答by sammy34
It seems that many answers to this question involve replacing the culture's percentage symbol with the empty string, and then parsing the resulting string as a numeric value.
似乎这个问题的许多答案都涉及用空字符串替换文化的百分比符号,然后将结果字符串解析为数值。
Perhaps I'm missing something, but there are still some unhandled cases here. Specifically, what happens if the PercentDecimalSeparator
is different to the NumberDecimalSeparator
for the current culture? What happens if the PercentGroupSeparator
is different to the NumberGroupSeparator
for the current culture? What happens if the PercentGroupSizes
are different to the NumberGroupSizes
?
也许我遗漏了一些东西,但这里仍有一些未处理的情况。具体来说,如果与当前文化的PercentDecimalSeparator
不同会发生什么NumberDecimalSeparator
?如果与当前文化PercentGroupSeparator
不同,会发生什么NumberGroupSeparator
?如果 与PercentGroupSizes
不同会发生什么NumberGroupSizes
?
Regardless of whether such a culture practically exists (if it doesn't, it may well come into existence in the future if the formatting for a culture is changed), I think that a better solution to the problem can be found if we consider these additional, special cases.
不管这样的文化实际上是否存在(如果不存在,如果改变文化的格式,将来很可能会存在),我认为如果我们考虑这些问题,可以找到更好的解决方案额外的、特殊的情况。
Here's a code snippet that shows a situation in which the other answers (based only on replacing the percent symbol) will fail, and a suggestion for how it could be done better properly:
这是一个代码片段,显示了其他答案(仅基于替换百分比符号)将失败的情况,以及如何更好地正确完成的建议:
// 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;
Yes, the code is a bit longer, and perhaps I'm being pedantic (i.e. maybe such a culture will never actually exist). That said, it seems to me to be a more general solution. Hope it helps somebody :).
是的,代码有点长,也许我是迂腐(即也许这样的文化永远不会真正存在)。也就是说,在我看来这是一个更通用的解决方案。希望它可以帮助某人:)。
回答by midspace
I'm not sure what it is with all this string replacement, substitution, and converters.
我不确定所有这些字符串替换、替换和转换器是什么。
Use the NumberFormat Currency portion, but fill it with the percent formats from your required culture.
使用 NumberFormat Currency 部分,但使用您所需区域性的百分比格式填充它。
// 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.
}