【问题标题】:Skip first splitting char in csv跳过csv中的第一个拆分字符
【发布时间】:2018-10-22 17:02:54
【问题描述】:

我输入了这样的 csv 文件:

 |Name|Surname|Age|
 |ABCD|DCBA|11|
 |QAZ|WSX|23|

当我尝试将 csv 文件上传到我的 datagridview 表时,我的第一列是空的,因为函数首先读取 | split char。

如何跳过每行中的第一个拆分字符?

部分代码:

file.ReadLine();
string line = "";
try
{
    while ((line = file.ReadLine()) != null)
    {
        string[] splitArray = line.Split('|');
        Listing.Add(new List(splitArray[0], splitArray[1], splitArray[2]));
        count++;
    }
}
catch
{
    MessageBox.Show("Nothing to do here...");
}
file.Close();

【问题讨论】:

  • 避免使用String.Split 解析文件,因为如果值包含| 字符,它会中断。考虑使用经过良好测试的 CSV 库,例如 nuget.org/packages/CsvHelper
  • String.Trim(char[]) 方法可能会有所帮助。您可以指定在进行拆分之前应从开头和结尾修剪的字符数组。 docs.microsoft.com/en-us/dotnet/api/…
  • @Dai 我在下面的答案中添加了一个 CsvHelper 示例。

标签: c# string winforms


【解决方案1】:

忽略第一个索引,使用splitArray[1]splitArray[2]splitArray[3](忽略splitArray[0]):

file.ReadLine();
string line = "";
try
{
    while ((line = file.ReadLine()) != null)
    {
        string[] splitArray = line.Split('|');
        Listing.Add(new List(splitArray[1], splitArray[2], splitArray[3]));
        count++;
    }
}
catch
{
    MessageBox.Show("Nothing to do here...");
}
file.Close();

正如其他人所指出的,为什么不使用CsvHelper

您可以通过非常简单的配置完成此操作:

public struct Listing
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
}

using (var file = File.OpenText("test.txt"))
{
    using (var csv = new CsvHelper.CsvReader(file))
    {
        csv.Configuration.Delimiter = "|";
        var records = csv.GetRecords<Listing>().ToList();

        foreach (var record in records)
        {
            Console.WriteLine("Name: {0}, Surname: {1}, Age: {2}", record.Name, record.Surname, record.Age);
        }
    }
}

在这里你可以看到一些示例输出:

【讨论】:

  • 如果需要 OP 对 sn 进行一些更改,我会避免使用 ToList,以避免不必要的内存分配,并使用 Skip(1) 和 Take(n) 使解决方案更加灵活-p.
  • 由于数据是从文件中设置的,因此我将重构您的解决方案以改用结构,因为该类没有任何行为,而您只是在文件中表示数据。重构应该让事情变得更快
  • @KevinAvignon 我一直是类的粉丝,因为它们通常更具可扩展性,因为他可能希望将来添加诸如 FullName 属性之类的方法(但我已经更新了代码)。至于.ToList(),我知道它会导致一个完整的枚举,而我这样做只是因为Listings原本是一个列表,我不确定他的使用计划是什么。为什么我要使用Skip(1)Take(n)
  • @KevinAvignon struct 在 C# 中与 class 相比具有不同的值类型语义,这意味着 structs 在运行时可能比 class 更昂贵,具体取决于使用场景,所以我不同意你的建议。此外,struct 可以有方法、实现接口和可变等等 - 所以说“结构没有行为”是不正确的。
  • 我 100% 同意你的观点,在大多数情况下,我倾向于和你一起去,但是当使用 using() {} 块时,如果他跳出循环(可能有一个 return 声明web API),IEnumerable 失败,因为文件流已关闭。这会给大多数新用户带来一些麻烦,所以我倾向于只使用.ToList() 以便在以后更轻松地访问(尽管这肯定会在更大的数据集上占用内存/性能)。
【解决方案2】:

您可以将可选的第二个StringSplitOptions 参数传递给RemoveEmptyEntries

string[] splitArray = line.Split('|', StringSplitOptions.RemoveEmptyEntries);

【讨论】:

  • (不是 DV),但是如果其中一个字段实际上包含一个空条目,这可能会导致一些问题。 (即|ABCD||11|
猜你喜欢
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多