У меня есть динамическая строка json:
[{
"Id": "1",
"Description": "Scenario 1",
"fc": "-45156,60000",
"fci": "-45156,60000",
"fcii": null,
"fciii": null,
"fciv": null,
},
{
"Id": "1",
"Description": "Scenario 2",
"fc": "-45156,60000",
"fci": "-45156,60000",
},
{
"Id": "1",
"Description": "Scenario 3",
"fc": "-45156,60000",
"fci": "-45156,60000",
"fcii": null,
},
{
"Id": "1",
"Description": "Scenario 4",
"fc": "-45156,60000",
}]
Стоит ли искать в объекте json строку, содержащую , идею
public decimal ConvertToDecimal(string s)
{
if (s.Contains(','))
{
return decimal.Parse(s.Replace(',', '.'));
}
else
return SomeDecimalValue;
}
Как я могу разобрать строку на десятичную и сохранить десятичный разделитель?
Я могу сказать вам sudo, если("123".contains(',')) разделить и попытаться проанализировать каждый из них, иначе попробуйте проанализировать результат
Это очень, очень плохая идея. JSON имеет отдельные обозначения для строк и десятичных знаков. "-45156,60000" не является десятичной дробью. -45156, 60000 и -45156.6 — десятичные дроби. Если вы хотите сериализовать координаты или пары значений, используйте правильную нотацию JSON — либо объект, либо массив.
Что означает «сохранять десятичный разделитель»? Вы знаете, что тип decimal вообще не имеет разделителя, и только строковое представление, основанное на текущей культуре, будет отображать разделитель? например. dotnetfiddle.net/lWBd6D
@MuhammadBashir, и тогда вам придется иметь дело с неправильными интерпретациями десятичных и тысячных разделителей. В JSON уже есть допустимые способы указания чисел и значений, поэтому людям не нужно разбивать и анализировать
Что должны содержать fc и fci? Одно значение или два? Если это десятичное число, то почему это строка, а не число? Реальное решение здесь — использовать хороший формат JSON, а не пытаться восстановиться из плохого и неоднозначного формата.
Кроме того, этот ConvertToDecimal уже сломан. В разных культурах используются разные форматы, и использование неправильного приведет к неверным значениям. Кто сказал, что , здесь десятичный разделитель? Проблема не может быть устранена путем произвольной замены разделителей. Если вы хотите анализировать числа с использованием определенной локали, все равно передайте ее Parse как CultureInfo, например decimal.Parse(str,CultureInfo.GetCultureInfo("fr-FR")). Однако вы должны знать, что такое правильный язык. В противном случае вы получите -4515660000
Если вы замените , на . и ваш код будет работать за пределами Китая и стран Тихоокеанского региона, decimal.Parse создаст -4515660000. Если бы не Китай, можно было бы сказать, что в большинстве стран мира то, что вы сделали, привело бы к неправильному результату.
Это вывод json, я не могу его изменить
Измените десятичный разделитель на ,. Вы можете переписать метод преобразования следующим образом:
public decimal? ConvertToDecimal(string s)
{
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-US");
culture.NumberFormat.NumberDecimalSeparator = ",";
if (string.IsNullOrWhiteSpace(s))
return null;
return Decimal.Parse(s, culture);//#,#
}
Добавить ссылку на Json.NET
ПОДХОД 1: Простой способ
public class Converted
{
public string Id { get; set; }
public string Description { get; set; }
public decimal? fc { get; set; }
public decimal? fci { get; set; }
public decimal? fcii { get; set; }
public decimal? fciii { get; set; }
public decimal? fciv { get; set; }
}
//from: https://json2csharp.com/
public class Root
{
public string Id { get; set; }
public string Description { get; set; }
public string fc { get; set; }
public string fci { get; set; }
public string fcii { get; set; }
public string fciii { get; set; }
public string fciv { get; set; }
//https://stackoverflow.com/questions/3013442/convert-string-to-decimal-retaining-the-exact-input-format
public Converted Convert() {
return new Converted()
{
Id = Id,
Description = Description,
fc = ConvertToDecimal(fc),
fci = ConvertToDecimal(fci),
fcii = ConvertToDecimal(fcii),
fciii = ConvertToDecimal(fciii),
fciv = ConvertToDecimal(fciv)
};
}
public decimal? ConvertToDecimal(string s)
{
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-US");
culture.NumberFormat.NumberDecimalSeparator = ",";
if (string.IsNullOrWhiteSpace(s))
return null;
return Decimal.Parse(s, culture);//#,#
}
}
Применение:
using Newtonsoft.Json;
using System.Globalization;
string json = File.ReadAllText("json1.json");
var obj = JsonConvert.DeserializeObject<List<Root>>(json);
List<Converted> ideal = new List<Converted>();
obj.ForEach(x =>
{
ideal.Add(x.Convert());
});
Console.WriteLine(ideal.Count);
ПОДХОД 2: Идеальный способ
Сверните свой собственный JsonConverter
public class Converted
{
public string Id { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(NiceDecimalConverter))]
public decimal? fc { get; set; }
[JsonConverter(typeof(NiceDecimalConverter))]
public decimal? fci { get; set; }
[JsonConverter(typeof(NiceDecimalConverter))]
public decimal? fcii { get; set; }
[JsonConverter(typeof(NiceDecimalConverter))]
public decimal? fciii { get; set; }
[JsonConverter(typeof(NiceDecimalConverter))]
public decimal? fciv { get; set; }
}
//from: https://stackoverflow.com/a/30083923/223752
public class NiceDecimalConverter : JsonConverter
{
public decimal? ConvertToDecimal(object o)
{
string s = Convert.ToString(o);
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-US");
culture.NumberFormat.NumberDecimalSeparator = ",";
if (string.IsNullOrWhiteSpace(s))
return null;
return Decimal.Parse(s, culture);//#,#
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var d = (decimal?)value;
if (!d.HasValue)
{
writer.WriteValue("null");
}
else
{
var niceLookingDecimal = d.ToString().Replace(".", ",");
writer.WriteValue(niceLookingDecimal);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ConvertToDecimal(reader.Value);
}
public override bool CanRead
{
get { return true; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(decimal?);
}
}
Применение:
string json = File.ReadAllText("json1.json");
var obj = JsonConvert.DeserializeObject<List<Converted>>(json,new NiceDecimalConverter());
Console.WriteLine(obj.Count);
Вы можете попробовать этот код
var jArr = JArray.Parse(json);
foreach (var item in jArr)
{
foreach (var prop in ((JObject)item).Properties())
{
if (prop.Name= = "Id" || prop.Name= = "Description") continue; //you can remove it
var val = ConvertToDecimal((string)prop.Value);
if (val != null) prop.Value = val;
}
}
json = jArr.ToString();
public decimal? ConvertToDecimal(string s)
{
if (!string.IsNullOrEmpty(s))
if (decimal.TryParse(s.Replace(',', '.'), out var val))
return val;
return null;
}
Поскольку никто не знает, что такое значение fc - это одно число или два, вы можете соответствующим образом изменить ConvertToDecimal.
Или вы можете десериализовать его, используя класс С#
List<Forecast> forecast= jArr.ToObject<List<Forecast>>();
public class Forecast
{
public int Id { get; set; }
public string Description { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Extra { get; set; }
}
Нет, это хорошая идея. Хорошая идея - использовать десятичный разбор попытки. десятичный вывод; decimal.TryParse("123", выход);