如果行/行不是以c#中已建立的字符开头,则跳过或删除CSV文件中的行/行

问题描述

这是我的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文件上的这些行,因为该行的开头不是numberN值或pipeline |

values of names 
values of names .|0|0|1|1|0|0||||

这是我后面的错误代码

索引超出范围。必须为非负数且小于 集合参数名称:index

如果该行不是以numberN的值或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,可能会对其进行调整

注意;我已经编写了它,但尚未对其进行调试/测试-它可能有错别字或较小的逻辑错误;将其视为伪代码

,

在我看来,当您遍历lines集合时,尝试更新同一行会使问题变得更加复杂。一种简单的方法(鉴于文件较小)是使用另一个仅包含“已批准”行的列表。

例如:

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要求的隐式循环之外),以插入文本