【问题标题】:Error when trying to Parse & Convert text from a .csv file尝试解析和转换 .csv 文件中的文本时出错
【发布时间】:2018-04-07 07:00:43
【问题描述】:

我目前一直在尝试使 .csv 文件中最后一列的输出正常工作。我需要将其转换为货币。我不确定我是否对整个列使用 (i == 6) (如果这甚至是可行的)或者我是否必须这样做 (i == 13 || i == 20 || i == 27) 等每个需要转换为货币的值。

我想要完成的事情:

当点击加载库存按钮时,将读取库存记录 使用打开文件对话框控件从文本文件中读取,从文件中读取的行被标记为字段值,解析(根据需要),然后加载到列表框和类实例列表中。除了输入文件中的所有字段值之外,ListBox(和类实例列表)还应包含 QtyHand 和 Sales 列。 String.Format() 或 PadRight() 方法可用于格式化列表框内容,以使列中的所有值都对齐(假设您使用的是等宽字体)。

.csv 文件的前两行是:

Id,Item Name,StartingQty,QtyMinRestck,QtySold,QtyRStcked,UnitPrice
85-0521031,Shampoo,35,9,0,0,2.89

非常感谢任何有关解决此问题的帮助。

public partial class inventoryForm : Form
{
    OpenFileDialog ipFile = new OpenFileDialog();
    public inventoryForm()
    {
        InitializeComponent();
    }

    private void loadInvDataButton_Click(object sender, EventArgs e)
    {
        inventoryListBox.Items.Clear(); //clear listbox items
        if (ipFile.ShowDialog() == DialogResult.OK) //show dialog box
        {
            string[] file = File.ReadAllLines(ipFile.FileName); //tokenize
            foreach (string line in file) //for each line in the file ...
            {
                string[] inventory = line.Split(','); //tokens contain numbers from the .csv file
                for (int i = 0; i < inventory.Length; i++) //loop goes through each item in the inventory
                {
                    if (i == 6) //items in the csv file that require conversion
                    {
                        double price = double.Parse(inventory[i]); //convert the value to currency, then pad
                        inventory[i] = String.Format("{0:C2}", price).PadRight(20, ' ');
                    }
                    else
                    {
                        inventory[i] = inventory[i].PadRight(20, ' '); //just pad the string
                    }
                }
                string item = string.Join("", inventory);
                inventoryListBox.Items.Add(item);
            }
        }
    }
}

【问题讨论】:

  • 欢迎来到 Stack Overflow! Stack Overflow 不是一个讨论论坛,它是一个问答网站,您可以在其中提出可以回答而不是讨论的特定编程问题。您的问题缺少 1)问题和 2)代码的明确问题陈述。请阅读How do I ask a good question? 和What topics can I ask about here?,然后编辑您的问题以符合站点指南。请记住,这不是双向对话,而是问题。
  • 我的第一反应是建议您在 Python 中执行此操作。你可以用不到一半的代码行数来做到这一点。 CSV 文件非常适合该语言,而且很容易学习。
  • @SDsolar - 这看起来像一个 WinForms 应用程序,那么为什么选择 Python 呢?您实际上可以使用 C# 和 linq 在一行中执行此操作...

标签: c# csv parsing for-loop openfiledialog


【解决方案1】:

我建议使这个面向对象,这看起来像 Inventory。所以第一步是做一个库存类。在 Inventory 类中会有一个方法以字符串作为文件名来加载库存(这可能需要根据您的实际数据类型和错误处理要求进行修改)。

    public class Inventory
    {
        public string Id { get; set; }
        public string ItemName { get; set; }
        public int StartingQty { get; set; }
        public int QtyMinRestck { get; set; }
        public int QtySold { get; set; }
        public int QtyRStcked { get; set; }
        public decimal UnitPrice { get; set; }

        public Inventory()
        {

        }

        //this overrides the default .ToString() method to provide
        //columnar output and formats the UnitPrice to currrency
        //this requires the following: using System.Globalization;
        public override string ToString()
        {
            return String.Format("{0}{1}{2}{3}{4}{5}{6}"
                , Id.PadRight(15, ' ')
                , ItemName.PadRight(30, ' ')
                , StartingQty.ToString().PadLeft(10, ' ')
                , QtyMinRestck.ToString().PadLeft(10, ' ')
                , QtySold.ToString().PadLeft(10, ' ')
                , QtyRStcked.ToString().PadLeft(10, ' ')
                , UnitPrice.ToString("C", CultureInfo.CurrentCulture).PadLeft(10, ' '));
        }

        //this loads a collection of inventory objects from a file
        //it would ignore any lines with errors
        public IEnumerable<Inventory> Load(string InventoryFileName)
        {
            var inventories = new List<Inventory>();

            using (var sr = new StreamReader(InventoryFileName))
            {
                sr.ReadLine(); //skip the first line
                while (!sr.EndOfStream)
                {
                    try
                    {
                        var fields = sr.ReadLine().Split(',');

                        inventories.Add(new Inventory
                        {
                            Id = fields[0]
                            ,
                            ItemName = fields[1]
                            ,
                            StartingQty = Int32.Parse(fields[2])
                            ,
                            QtyMinRestck = Int32.Parse(fields[3])
                            ,
                            QtySold = Int32.Parse(fields[4])
                            ,
                            QtyRStcked = Int32.Parse(fields[5])
                            ,
                            UnitPrice = Decimal.Parse(fields[6])
                        });
                    }
                    catch
                    {
                        //handle error here
                    }


                }
            }

            return inventories;
        }
    }

现在我们有了类,您可以轻松调用它并从文件中取回您的库存:

inventoryListBox.Items.Clear(); //清除列表框项

    if (ipFile.ShowDialog() == DialogResult.OK) //show dialog box
    {
        Inventory inventory = new Inventory();
        var inventories = inventory.Load(ipFile.FileName);
        //sets the datasource of the list box to the collection of inventory
        //by default it calls the ToString() method which which overrode
        //to provide columar output
        inventoryListBox.DataSource = inventories;
    }

这是一个非常基本的实现,但它应该使将来更容易维护。您还可以使用“库存”作为列表框的数据源。

【讨论】:

  • 您好,感谢您的帮助。我已经添加了这段代码,但我不确定我应该在 form.cs 代码中更改/修改什么。很抱歉成为这样的菜鸟。我应该删除所有东西并用这个来调用库存吗? ----------> 库存库存 = new Inventory(); var inventory = inventory.Load(@"c:\temp\inventory.txt"); -------------------我当前的输出是this之前的旧输出是this
  • 您可以用两行代码替换您的 for 循环以加载库存(将 c:\temp\inventory.txt 替换为 ipFile.Filename)。对于您的列表框,这取决于您要显示的内容。您可以覆盖类中的 ToString 或切换到 GridView 或其他旨在显示列数据的控件。如果这还不够信息,您将不得不展示您当前的工作并提出另一个问题。
  • 好的,所以我现在将输出加载到列表框中,但它是unformatted。我不知道为什么..Here's the form.cs 和Inventory class。当我输入 if (i == 6) 时,尝试将 csv 文件加载到列表框中时出现错误。我输入 (i == 13 || i == 20 || i == 27) 来尝试查看 csv 文件中的这些值是否会转换为 $。
  • ToString 方法中有this error。我不知道如何解决这个问题。所以我通过删除“CultureInfo.CurrentCulture”进行了临时修复,只是为了看看输出如何。将 .csv 文件中的第一行保留为标题的最佳方法是什么? Right now only the values in each column are showing without headers.
  • 如果你愿意的话。你能添加一些cmets吗?我只是想把所有事情都集中起来,并真正理解你所做的编码。
【解决方案2】:

好吧,这是没有其他细节的快速解决方案,但简而言之,您需要存储新格式化的项目的方法,我希望这对您来说足够清楚。更新为格式更好的代码。

static void Main(string[] args)
    {
        List<string> outputList = new List<string>();
        string[] list = new string[] { "85 - 0521031, Shampoo, 35, 9, 0, 0, 2.89", "86 - 0521031, Guitar, 35, 9, 0, 0, 9.89" };
        for(var i=0; i<list.Length; i++)
        {
            var listItem = list[i].Split(',');
            var outputListItem = "";

            for (var j=0; j<listItem.Length; j++)
            {
                if(j == 6)
                {
                    double price = double.Parse(listItem[j]);
                    listItem[j] = String.Format("{0:C2}", price).PadRight(20, ' '); ;
                }
                outputListItem = string.Join(" ", listItem);
            }

            Console.WriteLine(outputListItem);
            outputList.Add(outputListItem);
        }
        Console.ReadLine();
    }

【讨论】:

    猜你喜欢
    • 2016-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多