Подтвердить что ты не робот

Как разбить csv, чьи столбцы могут содержать,

Учитывая

2,1016,7/31/2008 14: 22, Джефф Далгас, 6/5/2011 22:21, /qaru.site/..., "Корваллис, ИЛИ", 7679,351,81, b437f461b3fd27387c5d8ab47a293d35,34

Как использовать С# для разделения приведенной выше информации на строки следующим образом:

2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://qaru.site/
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34

Как вы видите, один из столбцов содержит, <= (Corvallis, OR)

//обновить// Основано на С# Regex Split - запятые вне кавычек

string[] result = Regex.Split(samplestring, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
4b9b3361

Ответ 1

Используйте класс Microsoft.VisualBasic.FileIO.TextFieldParser. Это будет обрабатывать разбор файла с разделителями, TextReader или Stream, где некоторые поля заключены в кавычки, а некоторые - нет.

Например:

using Microsoft.VisualBasic.FileIO;

string csv = "2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,\"Corvallis, OR\",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";

TextFieldParser parser = new TextFieldParser(new StringReader(csv));

// You can also read from a file
// TextFieldParser parser = new TextFieldParser("mycsvfile.csv");

parser.HasFieldsEnclosedInQuotes = true;
parser.SetDelimiters(",");

string[] fields;

while (!parser.EndOfData)
{
    fields = parser.ReadFields();
    foreach (string field in fields)
    {
        Console.WriteLine(field);
    }
} 

parser.Close();

Это должно привести к следующему выводу:

2
1016
7/31/2008 14:22
Geoff Dalgas
6/5/2011 22:21
http://stackoverflow.com
Corvallis, OR
7679
351
81
b437f461b3fd27387c5d8ab47a293d35
34

Подробнее см. Microsoft.VisualBasic.FileIO.TextFieldParser.

Вам нужно добавить ссылку на Microsoft.VisualBasic на вкладке Добавить ссылки .NET.

Ответ 2

Уже так поздно, но это может быть полезно для кого-то. Мы можем использовать RegEx как ниже.

Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
String[] Fields = CSVParser.Split(Test);

Ответ 3

Вы можете разделить на все запятые, у которых есть четное число кавычек, следующих за ними.

Вы также хотели бы посмотреть на specf для формата CSV для обработки запятой.

Полезная ссылка: C# Regex Split - commas outside quotes

Ответ 4

Используйте библиотеку, например LumenWorks, чтобы выполнить чтение CSV. Он будет обрабатывать поля с кавычками в них и, скорее всего, в целом будет более надежным, чем ваше пользовательское решение, поскольку он существует долгое время.

Ответ 5

Я вижу, что если вы вставляете csv-разделительный текст в Excel и выполняете "Text to Columns", он запрашивает у вас "текстовый определитель". Он по умолчанию имеет двойную кавычку, так что он обрабатывает текст в двойных кавычках как литерал. Я полагаю, что Excel реализует это, перейдя по одному символу за раз, если он встречает "классификатор текста", он продолжает переходить к следующему "определителю". Вы, вероятно, можете реализовать это самостоятельно с помощью цикла for и логического значения, чтобы обозначить, если вы находитесь в буквальном тексте.

public string[] CsvParser(string csvText)
{
    List<string> tokens = new List<string>();

    int last = -1;
    int current = 0;
    bool inText = false;

    while(current < csvText.Length)
    {
        switch(csvText[current])
        {
            case '"':
                inText = !inText; break;
            case ',':
                if (!inText) 
                {
                    tokens.Add(csvText.Substring(last + 1, (current - last)).Trim(' ', ',')); 
                    last = current;
                }
                break;
            default:
                break;
        }
        current++;
    }

    if (last != csvText.Length - 1) 
    {
        tokens.Add(csvText.Substring(last+1).Trim());
    }

    return tokens.ToArray();
}

Ответ 6

Весьма сложно проанализировать файлы .csv, когда файл .csv может быть разделен запятыми, строками, разделенными запятыми, или хаотичной комбинацией этих двух. Решение, которое я придумал, позволяет использовать любую из трех возможностей.

Я создал метод ParseCsvRow(), который возвращает массив из строки csv. Сначала я использую двойные кавычки в строке, разделив строку на двойные кавычки на массив с именем quotesArray. Строковые. CSV файлы действительны только в том случае, если существует четное число двойных кавычек. Двойные кавычки в значении столбца следует заменить на пару двойных кавычек (это подход Excel). Пока CSV файл соответствует этим требованиям, вы можете ожидать, что разделители-разделители появятся только за пределами пар двойных кавычек. Запятые внутри пар двойных кавычек являются частью значения столбца и должны игнорироваться при расщеплении .csv в массив.

Мой метод будет проверять запятые вне пар двойных кавычек, просматривая только четные индексы quotesArray. Он также удаляет двойные кавычки из значений начала и конца столбца.

    public static string[] ParseCsvRow(string csvrow)
    {
        const string obscureCharacter = "ᖳ";
        if (csvrow.Contains(obscureCharacter)) throw new Exception("Error: csv row may not contain the " + obscureCharacter + " character");

        var unicodeSeparatedString = "";

        var quotesArray = csvrow.Split('"');  // Split string on double quote character
        if (quotesArray.Length > 1)
        {
            for (var i = 0; i < quotesArray.Length; i++)
            {
                // CSV must use double quotes to represent a quote inside a quoted cell
                // Quotes must be paired up
                // Test if a comma lays outside a pair of quotes.  If so, replace the comma with an obscure unicode character
                if (Math.Round(Math.Round((decimal) i/2)*2) == i)
                {
                    var s = quotesArray[i].Trim();
                    switch (s)
                    {
                        case ",":
                            quotesArray[i] = obscureCharacter;  // Change quoted comma seperated string to quoted "obscure character" seperated string
                            break;
                    }
                }
                // Build string and Replace quotes where quotes were expected.
                unicodeSeparatedString += (i > 0 ? "\"" : "") + quotesArray[i].Trim();
            }
        }
        else
        {
            // String does not have any pairs of double quotes.  It should be safe to just replace the commas with the obscure character
            unicodeSeparatedString = csvrow.Replace(",", obscureCharacter);
        }

        var csvRowArray = unicodeSeparatedString.Split(obscureCharacter[0]); 

        for (var i = 0; i < csvRowArray.Length; i++)
        {
            var s = csvRowArray[i].Trim();
            if (s.StartsWith("\"") && s.EndsWith("\""))
            {
                csvRowArray[i] = s.Length > 2 ? s.Substring(1, s.Length - 2) : "";  // Remove start and end quotes.
            }
        }

        return csvRowArray;
    }

Единственным недостатком моего подхода является то, что я временно заменяю запятые разделителем неясным символом юникода. Этот персонаж должен быть таким неясным, он никогда не появится в вашем CSV файле. Возможно, вы захотите сделать больше обработки.

Ответ 7

У меня возникла проблема с CSV, которая содержит поля с символом кавычки в них, поэтому, используя TextFieldParser, я придумал следующее:

private static string[] parseCSVLine(string csvLine)
{
  using (TextFieldParser TFP = new TextFieldParser(new MemoryStream(Encoding.UTF8.GetBytes(csvLine))))
  {
    TFP.HasFieldsEnclosedInQuotes = true;
    TFP.SetDelimiters(",");

    try 
    {           
      return TFP.ReadFields();
    }
    catch (MalformedLineException)
    {
      StringBuilder m_sbLine = new StringBuilder();

      for (int i = 0; i < TFP.ErrorLine.Length; i++)
      {
        if (i > 0 && TFP.ErrorLine[i]== '"' &&(TFP.ErrorLine[i + 1] != ',' && TFP.ErrorLine[i - 1] != ','))
          m_sbLine.Append("\"\"");
        else
          m_sbLine.Append(TFP.ErrorLine[i]);
      }

      return parseCSVLine(m_sbLine.ToString());
    }
  }
}

StreamReader по-прежнему используется для чтения CSV по строкам, как показано ниже:

using(StreamReader SR = new StreamReader(FileName))
{
  while (SR.Peek() >-1)
    myStringArray = parseCSVLine(SR.ReadLine());
}

Ответ 8

С Cinchoo ETL - библиотекой с открытым исходным кодом, она может автоматически обрабатывать значения столбцов, содержащие разделители.

string csv = @"2,1016,7/31/2008 14:22,Geoff Dalgas,6/5/2011 22:21,http://stackoverflow.com,""Corvallis, OR"",7679,351,81,b437f461b3fd27387c5d8ab47a293d35,34";

using (var p = ChoCSVReader.LoadText(csv)
    )
{
    Console.WriteLine(p.Dump());
}

Выход:

Key: Column1 [Type: String]
Value: 2
Key: Column2 [Type: String]
Value: 1016
Key: Column3 [Type: String]
Value: 7/31/2008 14:22
Key: Column4 [Type: String]
Value: Geoff Dalgas
Key: Column5 [Type: String]
Value: 6/5/2011 22:21
Key: Column6 [Type: String]
Value: http://stackoverflow.com
Key: Column7 [Type: String]
Value: Corvallis, OR
Key: Column8 [Type: String]
Value: 7679
Key: Column9 [Type: String]
Value: 351
Key: Column10 [Type: String]
Value: 81
Key: Column11 [Type: String]
Value: b437f461b3fd27387c5d8ab47a293d35
Key: Column12 [Type: String]
Value: 34

Для получения дополнительной информации, пожалуйста, посетите статью codeproject.

Надеюсь, поможет.

Ответ 9

"Test1 Real Estate Investment Trust" ("TEst1 REIT??", код акции: 1426) - это инвестиционный траст в сфере недвижимости, который инвестирует в высококачественную доходную недвижимость. Test1 REIT, зарегистрированная 5 декабря 2013 года на фондовой бирже xyz abc, является первым xyz abc REIT, предложившим прямое подключение к двум офисным зданиям премиум-класса, стратегически расположенным в Центральном деловом районе ("CBD??") компании. предложить Unitholders стабильные дистрибуции и потенциал для устойчивого долгосрочного роста за счет инвестиций в диверсифицированный портфель приносящей доход недвижимости по всему миру. Test1 REIT управляется Test1 Asset Management Limited ("Менеджер??"), компания, зарегистрированная в xyz abc и на 90,2% принадлежит 123 Investment Co., Limited (ранее известной как 45 Capital Co., Ltd., название изменено с 1 января 2016 года), которая является инвестиционной фирмой в области прямых инвестиций, котирующейся на фондовой бирже jkl (код акции).: 7190)

Здесь я могу видеть нечетное количество цитат в строке, и это создает некоторые проблемы при сопоставлении с Regex.