如何拆分和求和一个字符串值的成员

时间:2019-06-06 06:50:44

标签: c# wpf

我有一个数据库列,它是一个文本字段,并且此文本字段包含的值看起来像

I=5212;A=97920;D=20181121|I=5176;A=77360;D=20181117|I=5087;A=43975;D=20181109

,有时可能会有所不同:

I=29;A=20009.34;D=20190712;F=300|I=29;A=2259.34;D=20190714;F=300

其中“ I”代表发票ID,“ A”代表发票金额,“ D”代表YYYYMMDD格式的日期,如果发票来自国外供应商,则“ F”代表原始外币价值。

我正在获取该列并将其绑定到一个带有标记为“显示金额”的按钮的数据网格。单击按钮时,它将获取选定的行并拆分字符串以提取“ A”

我需要获取列结果中A =的所有部分...即

A=97920
A=77360
A=43975

然后将它们加在一起并在标签上显示结果。

我尝试使用'|'分割首先,提取子字符串'A =',然后使用';'进行拆分在“ =”之后获取金额。


string cAlloc;
string[] amount;
string InvoiceTotal;
string SupplierAmount;
string BalanceUnpaid;           

DataRowView dv = invoicesDataGrid.SelectedItem as DataRowView;

if (dv != null)
 {
   cAlloc = dv.Row.ItemArray[7].ToString();
   InvoiceTotal = dv.Row.ItemArray[6].ToString();

    if (invoicesDataGrid.Columns[3].ToString() == "0")
    {
       lblAmount.Foreground = Brushes.Red;
       lblAmount.Content = "No Amount Has Been Paid Out to the Supplier";
    }
    else
    {
       amount = cAlloc.Split('|');

       foreach (string i in amount)
       {
         string toBeSearched = "A=";
         string code = i.Substring(i.IndexOf(toBeSearched) + toBeSearched.Length);
          string[] res = code.Split(';');

          SupplierAmount = res[0];

          float InvTotIncl = float.Parse(InvoiceTotal, CultureInfo.InvariantCulture.NumberFormat);
          float AmountPaid = float.Parse(SupplierAmount, CultureInfo.InvariantCulture.NumberFormat);
          float BalUnpaid = InvTotIncl - AmountPaid;
          BalanceUnpaid = Convert.ToString(BalUnpaid);
          if (BalUnpaid == 0)
          {
            lblAmount.Content = "Amount Paid = " + SupplierAmount + "  No Balance Remaining, Supplier Invoice Paid in Full";
          }
          else if (BalUnpaid < 0)
          {
            lblAmount.Content = "Amount Paid = " + SupplierAmount + "  Supplier Paid an Excess of " + BalanceUnpaid;
          }
          else
          {
            lblAmount.Content = "Amount Paid = " + SupplierAmount + "  You Still Owe the Supplier a Total of " + BalanceUnpaid; ;
           }
         }

}

但是我只能提取A = 43975,最后一个“ A =“。除了全部三个以外,我还没有弄清楚如何对字符串求和。有人帮助...请。

4 个答案:

答案 0 :(得分:2)

正则表达式是首选解决方案。或者拆分,拆分和拆分。

  var cAlloc = "I=29;A=20009.34;D=20190712;F=300|I=29;A=2259.34;D=20190714;F=300";
  var amount = cAlloc.Split('|');

  decimal sum = 0;
  foreach (string i in amount)
  {
    foreach (var t in i.Split(';'))
    {
      var p = t.Split('=');
      if (p[0] == "A")
      {
        var s = decimal.Parse(p[1], CultureInfo.InvariantCulture);
        sum += s;
        break;
      }
    }
  }

答案 1 :(得分:1)

如果发票金额始终位于集合中的第二个值,则可以在拆分后通过索引直接访问它:

var str = "I=5212;A=97920;D=20181121|I=5176;A=77360;D=20181117|I=5087;A=43975;D=20181109";

var invoices = str.Trim().Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);

var totalSum = 0M;

foreach (var invoice in invoices)
{
    var invoiceParts = invoice.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

    var invoiceAmount = decimal.Parse(invoiceParts[1].Trim().Substring(2));

    totalSum += invoiceAmount;
}

否则,您可以使用更多“灵活”的解决方案,例如:

var str = "I=5212;A=97920;D=20181121|I=5176;A=77360;D=20181117|I=5087;A=43975;D=20181109";

var invoices = str.Trim().Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);

var totalSum = 0M;

foreach (var invoice in invoices)
{
    var invoiceParts = invoice.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

    var invoiceAmount = decimal.Parse(invoiceParts.First(ip => ip.Trim().ToLower().StartsWith("a=")).Substring(2));

    totalSum += invoiceAmount;
}

答案 2 :(得分:1)

var in1 = "I=5212;A=97920;D=20181121|I=5176;A=77360;D=20181117|I=5087;A=43975;D=20181109";
var in2 = "I=29;A=20009.34;D=20190712;F=300|I=29;A=2259.34;D=20190714;F=300";
var reg = @"A=(\d+(\.\d+)?)";

Regex.Matches(in1, reg).OfType<Match>().Sum(m => double.Parse(m.Groups[1].Value));
Regex.Matches(in2, reg).OfType<Match>().Sum(m => double.Parse(m.Groups[1].Value));

对于这样的事情,您正在做过多的工作。这是使用Regex的简单解决方案。

答案 3 :(得分:1)

导入输入:“ 反序列化

在以下给出的输入下,我们获得了具有属性名称I,A和D的对象列表。

var input = "I=5212;A=97920;D=20181121|I=5176;A=77360;D=20181117|I=5087;A=43975;D=20181109";

给出这个简单的类:

public class inputClass
{
    public decimal I { get; set; }
    public decimal A { get; set; }
    public decimal D { get; set; }
}

解析后的样子:

var inputItems =
        input.Split('|')
            .Select(
                x =>
                x.Split(';')
                 .ToDictionary(
                    y => y.Split('=')[0],
                    y => y.Split('=')[1]
                 )
            )
            .Select(
                x => //Manual parsing from dictionary to inputClass. 
                //If dictionary Key match an object property we could use something more generik.
                new inputClass
                {
                    I = decimal.Parse(x["I"], CultureInfo.InvariantCulture.NumberFormat),
                    A = decimal.Parse(x["A"], CultureInfo.InvariantCulture.NumberFormat),
                    D = decimal.Parse(x["D"], CultureInfo.InvariantCulture.NumberFormat),
                }
            )
            .ToList();

看起来很复杂吗?让inputClass负责根据字符串自行初始化 PropertyName=Value[; PropertyName=Value]

public inputClass(string input, NumberFormatInfo numberFormat)
{
    var dict = input
                 .Split(';')
                 .ToDictionary(
                    y => y.Split('=')[0],
                    y => y.Split('=')[1]
                 );

    I = decimal.Parse(dict["I"], numberFormat);
    A = decimal.Parse(dict["A"], numberFormat);
    D = decimal.Parse(dict["D"], numberFormat);
}

然后解析很简单:

var inputItems = input.Split('|').Select(x => new inputClass(x, CultureInfo.InvariantCulture.NumberFormat));

一旦我们有了一个更有用的结构,即对象列表,我们就可以轻松地计算Sum,Avg,Max,Min:

var sumA = inputItems.Sum(x => x.A);

产生输出:“ 序列化

为了处理输入,我们将定义一个类似于Input的对象

public class outputClass
{
    public decimal I { get; set; }
    public decimal A { get; set; }
    public decimal D { get; set; }
    public decimal F { get; set; }

该类应该能够产生字符串PropertyName=Value[; PropertyName=Value],:

public override string ToString()
{
    return $"I={I};A={A};D={D};F={F}";
}

然后在基于List输入的ListOutput上生成并字符串化“序列化”:

//process The input into the output.
var outputItems = new List<outputClass>();
foreach (var item in inputItems)
{
    // compute things to be able to create the nex output item
    item.A++;
    outputItems.Add(
            new outputClass { A = item.A, D = item.D, I = item.I, F = 42 }
        );
}           

// "Serialisation" 
var outputString = String.Join("|", outputItems);

在线演示。 https://dotnetfiddle.net/VcEQmf

长话短说:

  • 使用您将要使用/显示的属性定义一个类。
  • 添加采用类似"I=5212;A=97920;D=20181121"这样的字符串的构造函数
    nb:字符串可能包含不会映射到对象的属性
  • 覆盖ToString(),以便轻松进行序列化。
    nb:未存储在对象中的属性和值将不在序列化结果中。

现在,您只需要在行/对象分隔符"|"上进行拆分,就可以开始使用实际对象了,而不必再关心那个奇怪的字符串了。


PS:
关于您的两种输入类型,有些误会,我在心理上将它们视为输入,输出。不要介意那些名字。它可以是同一类。在此答案中它没有任何改变。