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



>我有一个数据库列,它是一个文本字段,这个文本字段包含看起来像

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="。而不是所有三个,而且我还没有弄清楚如何对字符串求和。有人帮忙...请。

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

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;
}
}
}
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));

你为这样的事情做了太多的工作。这是一个使用正则表达式的更简单的解决方案。

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

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;
}

导入输入:">反序列化">

通过以下给定的输入,我们有一个属性名称为 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));

一旦我们有一个更可用的结构 一个对象列表 我们可以很容易地计算总和、平均、最大值、最小值:

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

生成输出:">序列化">

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

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}";
}

然后在根据列表输入计算 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 的字符串的构造函数:String 可能包含不会映射到对象的属性
  • 覆盖ToString(),以便它可以轻松生成它的序列化。
    nb:未存储在对象中的属性和值将不会出现在序列化结果中。

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


PS:
对你的2种输入有一点误解,我在心理上把它们看作是输入,输出。不要介意那些名字。它可以是同一个类。它不会改变这个答案中的任何内容。

最新更新