我正在以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();
适用于以下问题:
任何建议都将不胜感激!
我还试图使用FileHelpers但似乎无法使用列的索引使其工作。
答案 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网站上有很好的实例,它解决了我的问题。希望这有助于其他人!