如果 line/row 不是以 c# 中已建立的字符开头,则跳过或删除 CSV 文件中的 line/row
Skip or delete line/row in CSV file if the line/row does not start with established character in c#
这是我的 CSV 文件
此文件由外部资源提供,并以带有管道分隔符的 csv 格式保存,我必须为此工作
||||||||||||||||||||||||||||||||||||||||||||||||||
|Table1|||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||
N|IDI |TEST|START DATE HOUR |CAUSE|KIND|NUMB|NAMES|
1|10704| |21/07/2020 15:05:54|L |MT |2786|NAV |
2|10660| |21/07/2020 09:27:31|L |MT |4088|PIS |
values of names
values of names .|0|0|1|1|0|0||||
||||||||||||||||||||||||||||||||||||||||||||||||||
|Table2|||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||
N|IDI |TEST|START DATE HOUR |END DATE HOUR |LENGHT |RETURNS |CAUSE|KIND|NUMB|NAMES|
1|10710| |21/07/2020 19:34:00|21/07/2020 20:19:09|00:45:09| - |L |MT |7806|ACC |
2|10708| |21/07/2020 18:28:12|21/07/2020 18:28:13|00:00:01| - |T |MT |2600|LIT |
3|10700| |21/07/2020 14:16:37|21/07/2020 15:19:13|01:02:36|21/07/2020 17:00|L |MT |4435|UHI |
4|10698| |21/07/2020 14:06:45|21/07/2020 14:07:22|00:00:37|- |B |MT |5789|TYK |
5|10674| |21/07/2020 10:21:04|21/07/2020 10:44:41|00:23:37|21/07/2020 12:30|T |MT |6699|FGR |
||||||||||||||||||||||||||||||||||||||||||||||||||
我需要删除或跳过 csv 文件中的这些行,因为该行不是以 number
或 N
值或 pipeline |
开头
values of names
values of names .|0|0|1|1|0|0||||
这是我的代码隐藏错误
Index was out of range. Must be non-negative and less than the size of
the collection parameter name:index
如果该行不是以 number
或 N
值或 pipeline |
开头
int posNewColumn = 4;
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
string[] CSVDump = File.ReadAllLines(input);
List<List<string>> CSV = CSVDump.Select(x => x.Split('|').ToList()).ToList();
foreach (List<string> line in CSV)
{
if (line[1] == "Table2")
{
break;
}
line.Insert(posNewColumn, line[0] == "N" ? "LENGHT" : string.Empty);
line.Insert(posNewColumn, line[0] == "N" ? "END DATE HOUR" : string.Empty);
}
File.WriteAllLines(output, CSV.Select(x => string.Join("|", x)));
如果一行中只有一个元素(如名称的行值),我需要跳过或删除行
你能帮帮我吗?
所以您想跳过所有以竖线开头的行?
List<List<string>> CSV = CSVDump
.Where(x => !x.StartsWith('|'))
.Select(x => x.Split('|').ToList()).ToArray();
所以您想保留任何以数字、N 或竖线开头的内容?
List<List<string>> CSV = CSVDump
.Where(x => x.Length > 0 && "0123456789N|".Contains(x[0]))
.Select(x => x.Split('|').ToList()).ToArray();
为了回应史蒂夫对性能等方面的担忧,也许最好的方法是:
int posNewColumn = 3;
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
using (var dest = File.CreateText(output))
{
bool adjust = true;
foreach (string s in File.ReadLines(input))
{
if(line.Length == 0 || !"0123456789N|".Contains(line[0]) //skip zero len or line not begin with number/pipe/N
continue;
string line = s; //copy enum variable so we can adjust it
if(adjust)
{
string[] bits = line.Split('|');
if(line.StartsWith("N"))
bits[posNewColumn] += "|END DATE HOUR|LENGHT";
else
bits[posNewColumn] += "||";
line = string.Join("|", bits);
}
if(line.StartsWith("|Table2")
adjust = false;
dest.WriteLine(line);
}
}
这需要最少的内存和处理;我们不会不必要地拆分每一行,不会创建数以千计的列表,我们不会尝试将整个文件保存在内存中;我们只是读入行,可能会写出,如果我们没有遇到 Table2
,可能会调整它们
注意;我已经写了,但不是 debugged/tested - 它可能有拼写错误或轻微的逻辑错误;将其视为伪代码
在我看来,您在遍历行集合时尝试更新同一行会使问题过于复杂。一种简单的方法(给定小文件大小)是使用另一个仅包含 'approved' 行的列表。
例如:
int posNewColumn = 4; // ???
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
List<string> outputLines = new List<string>();
foreach (string line in File.ReadLines(input))
{
var parts = line.Split('|').ToList();
if (parts.Count > 1)
{
if (parts[1] == "Table2")
{
break;
}
// Add here all the conditions that allow a line to be
// written in the output file
char c = parts[0][0];
if(c == '|' || c == 'N' || char.IsDigit(c))
{
parts.Insert(posNewColumn, parts[0] == "N" ? "LENGHT" : string.Empty);
parts.Insert(posNewColumn, parts[0] == "N" ? "END DATE HOUR" : string.Empty);
outputLines.Add(string.Join("|", parts);
}
}
}
File.WriteAllLines(output, outputLines);
此解决方案还包括将新文本添加到批准用于输出的行中的部分。虽然使用 Linq 用单行解析包含检查,但您需要另一个循环(除了 Linq 所需的隐式循环)来插入文本
这是我的 CSV 文件
此文件由外部资源提供,并以带有管道分隔符的 csv 格式保存,我必须为此工作
||||||||||||||||||||||||||||||||||||||||||||||||||
|Table1|||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||
N|IDI |TEST|START DATE HOUR |CAUSE|KIND|NUMB|NAMES|
1|10704| |21/07/2020 15:05:54|L |MT |2786|NAV |
2|10660| |21/07/2020 09:27:31|L |MT |4088|PIS |
values of names
values of names .|0|0|1|1|0|0||||
||||||||||||||||||||||||||||||||||||||||||||||||||
|Table2|||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||
N|IDI |TEST|START DATE HOUR |END DATE HOUR |LENGHT |RETURNS |CAUSE|KIND|NUMB|NAMES|
1|10710| |21/07/2020 19:34:00|21/07/2020 20:19:09|00:45:09| - |L |MT |7806|ACC |
2|10708| |21/07/2020 18:28:12|21/07/2020 18:28:13|00:00:01| - |T |MT |2600|LIT |
3|10700| |21/07/2020 14:16:37|21/07/2020 15:19:13|01:02:36|21/07/2020 17:00|L |MT |4435|UHI |
4|10698| |21/07/2020 14:06:45|21/07/2020 14:07:22|00:00:37|- |B |MT |5789|TYK |
5|10674| |21/07/2020 10:21:04|21/07/2020 10:44:41|00:23:37|21/07/2020 12:30|T |MT |6699|FGR |
||||||||||||||||||||||||||||||||||||||||||||||||||
我需要删除或跳过 csv 文件中的这些行,因为该行不是以 number
或 N
值或 pipeline |
values of names
values of names .|0|0|1|1|0|0||||
这是我的代码隐藏错误
Index was out of range. Must be non-negative and less than the size of the collection parameter name:index
如果该行不是以 number
或 N
值或 pipeline |
int posNewColumn = 4;
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
string[] CSVDump = File.ReadAllLines(input);
List<List<string>> CSV = CSVDump.Select(x => x.Split('|').ToList()).ToList();
foreach (List<string> line in CSV)
{
if (line[1] == "Table2")
{
break;
}
line.Insert(posNewColumn, line[0] == "N" ? "LENGHT" : string.Empty);
line.Insert(posNewColumn, line[0] == "N" ? "END DATE HOUR" : string.Empty);
}
File.WriteAllLines(output, CSV.Select(x => string.Join("|", x)));
如果一行中只有一个元素(如名称的行值),我需要跳过或删除行
你能帮帮我吗?
所以您想跳过所有以竖线开头的行?
List<List<string>> CSV = CSVDump
.Where(x => !x.StartsWith('|'))
.Select(x => x.Split('|').ToList()).ToArray();
所以您想保留任何以数字、N 或竖线开头的内容?
List<List<string>> CSV = CSVDump
.Where(x => x.Length > 0 && "0123456789N|".Contains(x[0]))
.Select(x => x.Split('|').ToList()).ToArray();
为了回应史蒂夫对性能等方面的担忧,也许最好的方法是:
int posNewColumn = 3;
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
using (var dest = File.CreateText(output))
{
bool adjust = true;
foreach (string s in File.ReadLines(input))
{
if(line.Length == 0 || !"0123456789N|".Contains(line[0]) //skip zero len or line not begin with number/pipe/N
continue;
string line = s; //copy enum variable so we can adjust it
if(adjust)
{
string[] bits = line.Split('|');
if(line.StartsWith("N"))
bits[posNewColumn] += "|END DATE HOUR|LENGHT";
else
bits[posNewColumn] += "||";
line = string.Join("|", bits);
}
if(line.StartsWith("|Table2")
adjust = false;
dest.WriteLine(line);
}
}
这需要最少的内存和处理;我们不会不必要地拆分每一行,不会创建数以千计的列表,我们不会尝试将整个文件保存在内存中;我们只是读入行,可能会写出,如果我们没有遇到 Table2
,可能会调整它们注意;我已经写了,但不是 debugged/tested - 它可能有拼写错误或轻微的逻辑错误;将其视为伪代码
在我看来,您在遍历行集合时尝试更新同一行会使问题过于复杂。一种简单的方法(给定小文件大小)是使用另一个仅包含 'approved' 行的列表。
例如:
int posNewColumn = 4; // ???
string input = @"C:\Temp\SO\import.csv";
string output = @"C:\Temp\SO\out.csv";
List<string> outputLines = new List<string>();
foreach (string line in File.ReadLines(input))
{
var parts = line.Split('|').ToList();
if (parts.Count > 1)
{
if (parts[1] == "Table2")
{
break;
}
// Add here all the conditions that allow a line to be
// written in the output file
char c = parts[0][0];
if(c == '|' || c == 'N' || char.IsDigit(c))
{
parts.Insert(posNewColumn, parts[0] == "N" ? "LENGHT" : string.Empty);
parts.Insert(posNewColumn, parts[0] == "N" ? "END DATE HOUR" : string.Empty);
outputLines.Add(string.Join("|", parts);
}
}
}
File.WriteAllLines(output, outputLines);
此解决方案还包括将新文本添加到批准用于输出的行中的部分。虽然使用 Linq 用单行解析包含检查,但您需要另一个循环(除了 Linq 所需的隐式循环)来插入文本