我试图创建一个函数,用一些最大长度变量打印账单的所有文章,但当超过这个最大长度时,会出现索引超出范围的错误,或者在其他情况下,总数和数量不会出现在行中:
最大长度变量:
private Int32 MaxCharPage = 36;
private Int32 MaxCharArticleName = 15;
private Int32 MaxCharArticleQuantity = 4;
private Int32 MaxCharArticleSellPrice = 6;
private Int32 MaxCharArticleTotal = 8;
private Int32 MaxCharArticleLineSpace = 1;
这是我目前的功能:
private IEnumerable<String> ArticleLine(Double Quantity, String Name, Double SellPrice, Double Total)
{
String QuantityChunk = (String)(Quantity).ToString("#,##0.00");
String PriceChunk = (String)(SellPrice).ToString("#,##0.00");
String TotalChunk = (String)(Total).ToString("#,##0.00");
// full chunks with "size" length
for (int i = 0; i < Name.Length / this.MaxCharArticleName; ++i)
{
String Chunk = String.Empty;
if (i == 0)
{
Chunk = QuantityChunk + new String((Char)32, (MaxCharArticleQuantity + MaxCharArticleLineSpace - QuantityChunk.Length)) +
Name.Substring(i * this.MaxCharArticleName, this.MaxCharArticleName) +
new String((Char)32, (MaxCharArticleLineSpace)) +
new String((Char)32, (MaxCharArticleSellPrice - PriceChunk.Length)) +
PriceChunk +
new String((Char)32, (MaxCharArticleLineSpace)) +
new String((Char)32, (MaxCharArticleTotal - TotalChunk.Length)) +
TotalChunk;
}
else
{
Chunk = new String((Char)32, (MaxCharArticleQuantity + MaxCharArticleLineSpace)) +
Name.Substring(i * this.MaxCharArticleName, this.MaxCharArticleName);
}
yield return Chunk;
}
if (Name.Length % this.MaxCharArticleName > 0)
{
String chunk = Name.Substring(Name.Length / this.MaxCharArticleName * this.MaxCharArticleName);
yield return new String((Char)32, (MaxCharArticleQuantity + MaxCharArticleLineSpace)) + chunk;
}
}
private void AddArticle(Double Quantity, String Name, Double SellPrice, Double Total)
{
Lines.AddRange(ArticleLine(Quantity, Name, SellPrice, Total).ToList());
}
例如:
private List<String> Lines = new List<String>();
private void Form1_Load(object sender, EventArgs e)
{
AddArticle(2.50, "EGGS", 0.50, 1.25); // Problem: Dont show the numbers like (Quantity, Sellprice, Total)
//AddArticle(100.52, "HAND SOAP /w EP", 5.00, 502.60); //OutOfRangeException
AddArticle(105.6, "LONG NAME ARTICLE DESCRIPTION", 500.03, 100.00);
//AddArticle(100, "LONG NAME ARTICLE DESCRIPTION2", 1500.03, 150003.00); // OutOfRangeException
foreach (String line in Lines)
{
Console.WriteLine(line);
}
}
控制台输出:
LINE1: EGGS
LINE2:105.6LONG NAME ARTIC 500.03 100.00
LINE3: LE DESCRIPTION
期望输出:
LINE:2.50 EGGS 0.50 1.25
LINE:100. HAND SOAP /w EP 5.00 502.60
LINE: 52
LINE:105. LONG NAME ARTIC 500.03 100.00
LINE: 60 LE DESCRIPTION
LINE:100. LONG NAME ARTIC 1,500. 150,003.
LINE: 00 LE DESCRIPTION2 03 00
您正试图获取值(最终是字符串值(并从中提取指定的长度(块(,其中给定组的每个单独块位于一行,下一个块位于下一行。在您发布的代码中有几个挑战。最大的问题之一是您可能不了解/
运算符的作用。当然,它用于除法,但它是整数除法,这意味着你会得到一个整数作为结果。例如3/15给你0,而17/15给你1。这意味着除非值的长度大于指定的块限制,否则循环永远不会运行。
另一个可能的问题是,您只对Name
执行此检查,而不对其他项目执行此检查(尽管出于简洁的原因,您可能省略了它们的代码(。
您当前的代码还创建了大量不必要的字符串,这将导致性能下降。请记住,在C#中,字符串是不可变的,这意味着它们不能更改。当您"更改"字符串的值时,实际上是在创建该字符串的另一个副本。
您的需求的关键是如何以获得正确输出的方式"组块"值。一种方法是创建一个扩展方法,该方法将接受一个字符串值并为您"chunkify"它。这里有一个这样的例子:将字符串拆分为块数组。我对它进行了一些修改,使其使用List<T>
,但数组也可以正常工作。
public static List<string> SplitIntoChunks(this string toSplit, int chunkSize)
{
int stringLength = toSplit.Length;
int chunksRequired = (int)Math.Ceiling(decimal)stringLength / (decimal)chunkSize);
List<string> chunks = new List<string>();
int lengthRemaining = stringLength;
for (int i = 0; i < chunksRequired; i++)
{
int lengthToUse = Math.Min(lengthRemaining, chunkSize);
int startIndex = chunkSize * i;
chunks.Add(toSplit.Substring(startIndex, lengthToUse));
lengthRemaining = lenghtRemaining - lengthToUse;
}
return chunks;
}
假设您有一个名为myString
的string
。您可以像这样使用上面的方法:string[] chunks = myString.SplitIntoChunks(15);
,并且您将收到一个由15个字符串组成的数组(取决于字符串的大小(。
代码的快速浏览(因为页面上没有太多解释(。块的大小被传递到扩展方法中。记录字符串的长度,并使用Math.Ceiling
函数确定该字符串的块的数量。
然后以所需块的数量为限制来构造for
循环。在循环内,确定块的长度(使用块大小或字符串的剩余长度中的较低者(,基于块大小和循环索引计算起始索引,然后通过Substring
提取块。最后计算剩余长度,一旦循环结束,就返回块。
在代码中使用此扩展方法的一种方法如下所示。扩展方法需要在一个单独的static
类中(我建议构建一个库,该库有一个专门用于扩展方法的类,因为它们非常方便(。请注意,我还没有时间测试这个,它对我的口味来说有点笨拙,但它至少应该让你朝着正确的方向前进。
private IEnumerable<string> ArticleLine(double quantity, string name, double sellPrice, double total)
{
List<string> quantityChunks = quantity.ToString("#,##0.00").SplitIntoChunks(maxCharArticleQuantity);
List<string> nameChunks = name.SplitIntoChunks(maxCharArticleName);
List<string> sellPriceChunks = sellPrice.ToString("#,##0.00").SplitIntoChunks(maxCharArticleSellPrice);
List<string> totalChunks = total.ToString("#,##0.00").SplitIntoChunks(maxCharArticleTotal);
int maxLines = (new List<int>() { quantityChunks.Count,
nameChunks.Count,
sellPriceChunks.Count,
totalChunks.Count }).Max();
for (int i = 0; i < maxLines; i++)
{
lines.Add(String.Format("{0}{1}{2}{3}",
quantityChunks.Count > i ?
quantityChunks[i].PadLeft(maxCharArticleQuantity) :
String.Empty.PadLeft(maxCharArticleQuantity),
nameChunks.Count > i ?
nameChunks[i].PadLeft(maxCharArticleName) :
String.Empty.PadLeft(maxCharArticleName, ' '),
sellPriceChunks.Count > i ?
sellPriceChunks[i].PadLeft(maxCharArticleSellPrice) :
String.Empty.PadeLeft(maxCharArticleSellPrice),
totalChunks.Count > i ?
totalChunks[i].PadLeft(maxCharArticleTotal) :
String.Empty.PadLeft(maxCharArticleTotal));
}
return lines;
}
上面的代码做了几件事。首先,它对四个变量中的每一个调用SplitIntoChunks
。
接下来,它使用Max()
扩展方法(如果您还没有对System.Linq
的引用,则需要添加一个对using
指令的引用(。以确定所需的最大行数(基于四个列表中的最高计数(。
最后,它使用4个for
循环来构建线路。请注意,我使用三元运算符(?:
(来构建每一行。我走这条路线的原因是为了使行的格式正确,即使4个值中的一个或多个值没有用于该行的内容。换句话说:
quantityChunks.Count > i
如果quantityChunks
中的项目数大于i
,则该行存在该项目的条目。
quanityChunks[i].PadLeft(maxCharArticleQuantity, ' ')
如果条件评估为true,我们使用相应的条目(并用空格填充以保持对齐(。
String.Empty.PadLeft(maxCharArticleQuantity, ' ')
如果条件为false,我们只需为行中该位置的最大字符数添加空格。
然后你可以像这样打印输出:
foreach(string line in lines)
{
Console.WriteLine(line);
}
在代码中,我检查String.Format
中的最大行数和使用三元运算符的部分对我来说非常笨拙,但我没有时间将其精细化为更令人尊敬的内容。我希望这至少能为你指明正确的方向。
编辑
修复了PadLeft
语法并删除了指定的字符,因为默认情况下使用空格。