C#处理CSV文件

时间:2018-09-18 13:18:44

标签: c# .net file csv

我有以下带有此标头的CSV文件:

AccountOwnerEmail PartnerName EnrollmentID Customer LicensingProgram Country Culture Issue

带有这样的行:

v-dakash@catalysis.com,"HEY"? Tester, 12345789,"Catalysis", LLC., Enterprise 6 TEST, etc,etc ,etc

我有一种方法可以将行分成相应的列:

var columns = columnsRegex.Matches(line)
                          .Cast<Match>()
                          .Select(m=> m.Value.Trim('\"', '\'', ' ', '\t'))
                          .ToList();

这是columnsRegex的定义:

private static Regex columnsRegex = new Regex("\"[^\"]*\"|'[^']*'|[^,;]+");

我的问题是,例如PartnerName的内容被分成3列,例如"" "Hey""?Tester"

我知道CSV转义了双引号和另一个双引号。而且我已经检查了与此类似的其他帖子,建议将其添加到Microsoft.VisualBasic,但这对我不起作用。是否还有其他方法可以正确处理CSV内容?

2 个答案:

答案 0 :(得分:2)

我使用CsvHelper。这是一个很好的库来解析CSV文档。使用nuget包:

Install-Package CsvHelper

可以找到文档here

var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyCsvRecord>();

MyCsvRecord是您的CSV行,例如:

public class MyCsvRecord
{
    public string AccountOwnerEmail { get; set; }
    public string PartnerName { get; set; }
    // etc.
}

答案 1 :(得分:1)

编辑:添加了另一种解析器方法,固定行和测试解析输出。

我会说,您的正则表达式模式是错误的。不允许在前缀"中使用"字符(加倍)。对于'

,同样的问题
internal static class Program
{
  private const string wrongLine = "v-dakash@catalysis.com,\"HEY\"? Tester, 12345789,\"Catalysis\", LLC., Enterprise 6 TEST, etc,etc ,etc";
  private const string fixedLine = "v-dakash@catalysis.com,\"\"\"HEY\"\"? Tester\", 12345789,\"Catalysis\", LLC., Enterprise 6 TEST, etc,etc ,etc";

  private static readonly Regex wrongPattern = new Regex("\"[^\"]*\"|'[^']*'|[^,;]+");
  private static readonly Regex fixedPattern = new Regex("((?:\"((?:[^\"]|\"\")*)\")|(?:'((?:[^']|'')*)')|([^,;]*))(?:[,;]|$)");

  private static void Main()
  {
    Console.WriteLine("***  Wrong line: ***");
    Console.WriteLine();
    Parse(wrongLine);

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine("***  Fixed line: ***");
    Console.WriteLine();
    Parse(fixedLine);
  }

  private static void Parse(string line)
  {
    Console.WriteLine("--- [Original Regex] ---");

    var matches = wrongPattern.Matches(line);
    for (int i = 0; i < matches.Count; i++)
    {
      Console.WriteLine("'" + matches[i].Value + "'");
    }

    Console.WriteLine();
    Console.WriteLine("--- [Fixed Regex] ---");
    Console.WriteLine();

    matches = fixedPattern.Matches(line);
    for (int i = 0; i < matches.Count; i++)
    {
      Console.WriteLine("'" + GetValue(matches[i]) + "'");
    }

    Console.WriteLine();
    Console.WriteLine("--- [Correct(?) parser] ---");
    Console.WriteLine();

    var position = 0;
    while (position < line.Length)
    {
      var value = GetValue(line, ref position);
      Console.WriteLine("'" + value + "'");
    }
  }

  private static string GetValue(Match match)
  {
    if (!string.IsNullOrEmpty(match.Groups[2].Value))
    {
      return (match.Groups[2].Value.Replace("\"\"", "\""));
    }

    if (!string.IsNullOrEmpty(match.Groups[3].Value))
    {
      return (match.Groups[3].Value.Replace("''", "'"));
    }

    return (match.Groups[4].Value.Replace("''", "'"));
  }

  private static string GetValue(string line, ref int position)
  {
    string value;
    char? prefix;
    string endWith;
    switch (line[position])
    {
    case '\'':
    case '\"':
      prefix = line[position];
      endWith = prefix + ",";
      position++;
      break;

    default:
      prefix = null;
      endWith = ",";
      break;
    }

    var endPosition = line.IndexOf(endWith, position);
    if (endPosition < 0 && prefix.HasValue)
    {
      if (line[line.Length - 1] == prefix.Value)
      {
        value = line.Substring(position, line.Length - 1 - position);
        position = line.Length;
        return Fixprefix(value, prefix.Value.ToString());
      }

      position--;
      endPosition = line.IndexOf(',', position);
    }

    if (endPosition < 0)
    {
      value = line.Substring(position);
      position = line.Length;
      return value;
    }

    if (prefix.HasValue)
    {
      value = line.Substring(position, endPosition - position);
      position = endPosition + endWith.Length;
      return Fixprefix(value, prefix.Value.ToString());
    }

    value = line.Substring(position, endPosition - position);
    position = endPosition + endWith.Length;
    return value;
  }

  private static string Fixprefix(string value, string prefix) => value.Replace(prefix + prefix, prefix);
}

“固定Regex模式”仍然存在错误,但我将其保留为当前状态...

(说明您自己如何解决此问题。)

Parser test

输出窗口:

***  Wrong line: ***

--- [Original Regex] ---
'v-dakash@catalysis.com'
'"HEY"'
'? Tester'
' 12345789'
'"Catalysis"'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'

--- [Fixed Regex] ---

'v-dakash@catalysis.com'
'"HEY"? Tester'
' 12345789'
'Catalysis'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'
''

--- [Correct(?) parser] ---

'v-dakash@catalysis.com'
'HEY"? Tester, 12345789,"Catalysis'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'


***  Fixed line: ***

--- [Original Regex] ---
'v-dakash@catalysis.com'
'""'
'"HEY"'
'"? Tester"'
' 12345789'
'"Catalysis"'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'

--- [Fixed Regex] ---

'v-dakash@catalysis.com'
'"HEY"? Tester'
' 12345789'
'Catalysis'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'
''

--- [Correct(?) parser] ---

'v-dakash@catalysis.com'
'"HEY"? Tester'
' 12345789'
'Catalysis'
' LLC.'
' Enterprise 6 TEST'
' etc'
'etc '
'etc'