根据selectedIndex将项添加到List

时间:2011-08-17 03:40:40

标签: c# csv

我正在以CSV格式读取文件:

10009279,D002158 ,,“Mount Robinson deposit”,38.1139,-105.34557,NA,“United States”,Colorado,Custer,B,“Aluminium,Potassium”,

我想基于初始CSV文件中的选定列写出新的CSV文件,因此生成的结构如下所示:

-105.34557,38.1139,“Mount Robinson矿床”,“Custer”铝,钾“

我试过了:

StreamWriter writer = new StreamWriter(@textBox2.Text);
string[] lines = File.ReadAllLines(@textBox1.Text);
foreach (string line in lines)
{
    string[] fields = line.Split(',');
    writer.WriteLine(string.Format("{0},{1},{2},{3}", fields[LONcomboBox.SelectedIndex], fields[LATcomboBox.SelectedIndex], fields[NAMEcomboBox.SelectedIndex], fields[10 + 13]));
}
writer.Close();

适用于以下问题:

    嵌入双引号的
  1. 逗号似乎无法正确处理
  2. 连接多个文件似乎失败了(感谢答案,这已得到解决)
  3. 任何建议都将不胜感激!

    我还试图使用FileHelpers但似乎无法使用列的索引使其工作。

5 个答案:

答案 0 :(得分:1)

好的。快速而又脏的简短回答我会使用Linq和Regex。

    private void processCSV(string inputFileName)
    {
        Regex regexObj = new Regex(@"\s*(?:""(?<val>""[^""]*(""""[^""]*)*"")\s*|(?<val>[^,]*))(?:,|$)");
        List<List<Match>> elements = File.ReadAllLines(inputFileName)
            .Select<string,List<Match>>(x=>regexObj.Matches(x).Cast<Match>().ToList()).ToList();            
        List<string> newLines = elements.Select(y=>y.Select(z=>z.Groups["val"].Value).ToList())
                                        .Select(z=>string.Format("{0},{1},{2},{3}",z[0],z[1],z[2],z[4]+z[5]))
                                        .ToList();

         //Write newlines somewhere
    }

但是对于生产级代码,您确实应该使用像http://www.codeproject.com/KB/database/CsvReader.aspx

这样的CSV解析器库

我确信有更好的那些是我见过的第一个。

答案 1 :(得分:0)

关于(a),  您是否可以控制csv输入文件的格式?如果是这样,那么一个简单的选择就是使用不同的分隔符来逗号。也许|代替?

回答(b),

而不是fields[10 + 13]

尝试fields[10] + fields[13]

否则您所做的只是尝试查找字段23,这可能不存在。

答案 2 :(得分:0)

你可能想找一个csv解析器,这里有一些很好的建议:High scoring answer on StackOverflow

你最后一个参数没有异常吗?

我想你想要更像的东西:

writer.WriteLine(的String.Format( “{0},{1},{2},{3}”, fields [LONcomboBox.SelectedIndex],fields [LATcomboBox.SelectedIndex],fields [NAMEcomboBox.SelectedIndex],fields [10] + fields [13]));

然而,我可能会对没有检查数组索引的人感到愤怒,所以请确保在引用字段[13]之前验证至少有14列。

答案 3 :(得分:0)

以下代码实现了解析器以及csv编写器

private void ProcessCSV(string sourceCsvFilePath, string destCsvFilePath)
{
    // Read contents of source file
    var lines = File.ReadAllLines(sourceCsvFilePath, Encoding.Default);

    // Process the old file contents
    var table = new List<List<string>>();
    foreach (var line in lines)
    {
        var cells = new List<string>();
        if (line[0] == ',')
        {
            cells.Add(string.Empty);
        }

        for (int i = 0; i < line.Length; i++)
        {
            if (line[i] == '\"')
            {
                var cellBuilder = new StringBuilder(line[i].ToString());
                i++;
                while (i < line.Length && line[i] != '\"')
                {
                    cellBuilder.Append(line[i].ToString());
                    i++;
                }
                cells.Add(cellBuilder.ToString().Trim('\"'));
            }
            else if (line[i] != ',')
            {
                var cellBuilder = new StringBuilder(line[i].ToString());
                i++;
                while (i < line.Length && line[i] != ',')
                {
                    cellBuilder.Append(line[i].ToString());
                    i++;
                }

                cells.Add(cellBuilder.ToString().Trim('\"'));
            }
            else if ( i > 0 && line[i - 1] == ',' && line[i] == ',')
            {
                cells.Add(string.Empty);
            }
        }

        if(line[line.Length - 1] == ',')
        {
            cells.Add(string.Empty);
        }

        table.Add(cells);
    }

    // Create a new table in the order: OldTable.Col2, OldTable.Col4, OldTable.Col0, "OldTable.Col1 OldTable.Col5 OldTable.Col6"
    var newTable = new List<List<string>>();

    foreach (var row in table)
    {
        var cells = new List<string>();
        cells.Add(row[2].Contains(',') ? string.Concat("\"", row[2], "\"") : row[2]);
        cells.Add(row[4].Contains(',') ? string.Concat("\"", row[4], "\"") : row[2]);
        cells.Add(row[0].Contains(',') ? string.Concat("\"", row[0], "\"") : row[2]);

        string str = string.Format("{0} {1} {2}", row[1], row[5], row[6]);
        cells.Add(str.Contains(',') ? string.Concat("\"", str, "\"") : str);

        newTable.Add(cells);
    }

    // Prepare the file contents
    var linesToWrite = new string[newTable.Count];
    int lineCounter = 0;
    foreach (var row in newTable)
    {
        StringBuilder rowBuilder = new StringBuilder();
        foreach (var cell in row)
        {
            rowBuilder.AppendFormat("{0},", cell);
        }

        linesToWrite[lineCounter++] = rowBuilder.ToString().Trim(',');
    }

    // Write the contents to CSV
    File.WriteAllLines(destCsvFilePath, linesToWrite, Encoding.Default);
}

您需要添加File.Exists的检查和索引检查(以确保在您访问该列之前该列存在)。 如果您对更简洁的方法感兴趣,那么您可以尝试使用带有Regex class的正则表达式进行解析。

答案 4 :(得分:0)

根据Doug的推荐,我查看了一些csv解析器。我首先尝试了FileHelpers,但是在使用标题行时我真的无法工作。对列的引用总是按列名进行,而不是索引。我真的需要通过列的索引来引用我的列,因为它匹配我的选择列表框和checkedlistbox。我回顾了A FAST CSV READER,它实际上为我做了诀窍。以下是我实现它的方式:

    private void button2_Click(object sender, EventArgs e)
    {

        using (CsvReader csv = new CsvReader(new StreamReader(@textBox1.Text), true))
        {
            int fieldCount = csv.FieldCount;
            string[] headers = csv.GetFieldHeaders();

            /// Evaluate the checkedlistbox
            string comment = "";
            List<Int32> comment_indices = new List<Int32>();
            List<String> lines = new List<String>();
            for (int x = 0; x <= checkedListBox1.CheckedItems.Count - 1; x++)
            {
                // add selected item's index to list
                comment_indices.Add(checkedListBox1.CheckedIndices[x]);
            }

            while (csv.ReadNextRecord())
            {

                ///  Use the SelectedIndex to match the header and column
                string base_string = csv[LONcomboBox.SelectedIndex] + "," + csv[LATcomboBox.SelectedIndex] + "," + csv[NAMEcomboBox.SelectedIndex] + ",";
                //MessageBox.Show(base_string);

                ///  Try to get the row value -- this is the row count - starting at 0 excluding headers I think
                //MessageBox.Show("Is this the row count?" + csv.CurrentRecordIndex);
                comment = "";
                ///  Get the comment
                foreach (Int32 indices in comment_indices)
                {
                    comment = comment + csv[indices] + " ";
                }
                //MessageBox.Show(base_string + '"' + comment + '"');
                string completed_string = base_string + '"' + comment + '"';
                lines.Add(completed_string);
            }

            StreamWriter writer = new StreamWriter(@textBox2.Text);
            foreach (string line in lines)
            {
                writer.WriteLine(line);
            }
            writer.Close(); 
        }          
        MessageBox.Show(" Finished Writing file " + "\n" + "\n" + " " + textBox2.Text);
    }

Code Project网站上有很好的实例,它解决了我的问题。希望这有助于其他人!