Я имею строку как "1,5%" и хочу преобразовать ее для удвоения значения.
Это может быть сделано простое со следующим:
public static double FromPercentageString(this string value)
{
return double.Parse(value.SubString(0, value.Length - 1)) / 100;
}
но я не хочу использовать этот подход парсинга.
Какой-либо другой подход с IFormatProvider или что-то вроде этого?
Если вы заботитесь об обнаружении ошибок форматирования, я бы использовал 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;
Использование Replace позволит вам успешно и ошибочно анализировать IMO такие вещи, как:
в дополнение к 1.5%
Это чувствительная к культуре, замените его так:
value = value.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
затем разбирать его.
Только немного лучше, но меньше ошибок:
public static double FromPercentageString(this string value)
{
return double.Parse(value.Replace("%","")) / 100;
}
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 );
}
}
Это строка, независимо от того, что вы делаете с этим, чтобы удалить знак%, вы все еще должны разобрать его в двойной.