Как обрабатывать разрывы строк в CSV файле с помощью С#?

У меня есть таблица Excel, которая преобразуется в CSV файл в С#, но у меня проблема с разрывами строк. Например:

"John","23","555-5555"

"Peter","24","555-5
555"

"Mary,"21","555-5555"

Когда я читаю CSV файл, если запись не начинается с двойной кавычки ("), тогда разрыв строки происходит по ошибке, и я должен удалить ее. У меня есть некоторые классы чтения CSV из Интернета, но я что они потерпят неудачу при разрыве линии.

Как я должен обрабатывать эти разрывы строк?


Спасибо всем за помощь.

heres - это то, что было сделано до сих пор, мои записи имеют фиксированный формат, и все начинаются с

JTW;...;....;...;

JTW;...;...;....

JTW;....;...;..

..;...;... (wrong record, line brak inserted)

JTW;...;...

поэтому я проверил ; в позиции [3] каждой строки. если true, я пишу, если false ill append на последнем * удалении прерывания строки)

У меня возникают проблемы, потому что im сохраняет файл как txt.

Кстати, я конвертирую excell spreadshit в csv, сохраняя как csv в excell. но я не уверен, что клиент делает это.

Итак, файл как TXT идеален. ive проверил записи и итоги. Но теперь мне нужно преобразовать его обратно в csv, и мне бы очень хотелось сделать это в программе. Кто-нибудь знает, как это сделать?

вот мой код:

namespace EditorCSV
{
    class Program
    {
        static void Main(string[] args)
        {
            ReadFromFile("c:\\source.csv");
    }


        static void ReadFromFile(string filename)
        {
            StreamReader SR;
            StreamWriter SW;
            SW = File.CreateText("c:\\target.csv");
            string S;
            char C='a';
            int i=0;
            SR=File.OpenText(filename);
            S=SR.ReadLine();
            SW.Write(S);
            S = SR.ReadLine();
            while(S!=null)
            {
                try { C = S[3]; }
                catch (IndexOutOfRangeException exception){
                    bool t = false;
                    while (t == false)
                    {
                        t = true;
                        S = SR.ReadLine();
                        try { C = S[3]; }
                        catch (IndexOutOfRangeException ex) { S = SR.ReadLine(); t = false; }

                    }
                }
                if( C.Equals(';'))
                {
                    SW.Write("\r\n" + S);
                    i = i + 1;
                }
                else
                {
                    SW.Write(S);

                }
                S=SR.ReadLine();
            }
            SR.Close();
            SW.Close();
            Console.WriteLine("Records Processed: " + i.ToString() + " .");
            Console.WriteLine("File Created SucacessFully");
            Console.ReadKey();


        }




        }
    } 

Ответ 1

В CSV есть предопределенные способы обработки этого. Этот сайт предоставляет легко читаемое объяснение стандартного способа обработки всех предостережений CSV.

Тем не менее, нет оснований не использовать твердую библиотеку с открытым исходным кодом для чтения и записи CSV файлов, чтобы избежать нестандартных ошибок. LINQtoCSV - моя любимая библиотека для этого. Он поддерживает чтение и запись простым и простым способом.

В качестве альтернативы этот SO-вопрос для CSV-библиотек предоставит вам список самых популярных вариантов.

Ответ 2

Вместо того, чтобы проверять отсутствие текущей строки ( ") в качестве первого символа, вместо этого проверьте, является ли последний символ (" ). Если это не так, вы знаете, что у вас разрыв строки, и вы можете прочитать следующую строку и объединить ее.

Я предполагаю, что данные вашего примера были точными - поля были заключены в кавычки. Если кавычки не могут отделять текстовое поле (или новые строки каким-то образом обнаруживаются в нетекстовых данных), тогда все ставки отключены!

Ответ 3

Существует встроенный метод чтения CSV файлов в .NET(требуется добавление ссылки на сборку Microsoft.VisualBasic):

public static IEnumerable<string[]> ReadSV(TextReader reader, params string[] separators)
{
    var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader);
    parser.SetDelimiters(separators);
    while (!parser.EndOfData)
        yield return parser.ReadFields();
}

Если вы имеете дело с действительно большими файлами, этот читатель CSV утверждает, что он самый быстрый из них: http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

Ответ 4

Недавно я использовал этот фрагмент кода для анализа строк из файла CSV (это упрощенная версия):

private void Parse(TextReader reader)
    {
        var row = new List<string>();
        var isStringBlock = false;
        var sb = new StringBuilder();

        long charIndex = 0;
        int currentLineCount = 0;

        while (reader.Peek() != -1)
        {
            charIndex++;

            char c = (char)reader.Read();

            if (c == '"')
                isStringBlock = !isStringBlock;

            if (c == separator && !isStringBlock) //end of word
            {
                row.Add(sb.ToString().Trim()); //add word
                sb.Length = 0;
            }
            else if (c == '\n' && !isStringBlock) //end of line
            {
                row.Add(sb.ToString().Trim()); //add last word in line
                sb.Length = 0;

                //DO SOMETHING WITH row HERE!

                currentLineCount++;

                row = new List<string>();
            }
            else
            {
                if (c != '"' && c != '\r') sb.Append(c == '\n' ? ' ' : c);
            }
        }

        row.Add(sb.ToString().Trim()); //add last word

        //DO SOMETHING WITH LAST row HERE!
    }

Ответ 5

Возможно, вы могли бы рассчитывать на ( ") во время ReadLine(). Если они нечетные, это поднимет флаг. Вы можете либо проигнорировать эти строки, либо получить следующие два и исключить первое появление \n" линии слияния.

Ответ 6

То, что я обычно делаю, это прочитать текст в символе символом, противоположным строковой строке, из-за этой самой проблемы.

Когда вы читаете каждый символ, вы должны выяснить, где каждая ячейка запускается и останавливается, а также разницу между строк в строке и в ячейке: если я правильно помню, для файлов сгенерированных Excel в любом случае, строки начинаются с \r\n, а строки в ячейках - только\r.

Ответ 7

Прислушайтесь к советам экспертов и Не сворачивайте свой собственный парсер CSV.

Ваша первая мысль: "Как мне обрабатывать новые разрывы строк?"

Ваша следующая мысль: "Мне нужно обрабатывать запятые внутри кавычек".

Ваша следующая мысль будет: "О, дерьмо, мне нужно обрабатывать кавычки внутри цитат. Сбежавшие цитаты. Двойные кавычки. Одиночные кавычки..."

Это дорога к безумию. Не пишите свои собственные. Найдите библиотеку с обширным охватом unit test, который поражает все тяжелые части и прошел через ад для вас. Для .NET используйте бесплатную библиотеку FileHelpers.

Ответ 8

Попробуйте CsvHelper (библиотека, которую я поддерживаю). Он игнорирует пустые строки. Я считаю, что есть флаг, который вы можете установить в FastCsvReader, чтобы он также обрабатывал пустые строки.

Ответ 9

Существует пример синтаксического анализатора С#, который, по-видимому, корректно обрабатывает ваш случай. Затем вы можете прочитать свои данные и очистить строку, выходящую из нее после чтения. Часть 2 является парсером, и есть Часть 1, который охватывает часть записи.

Ответ 10

Прочитайте строку.
Разделить на столбцы (поля).
Если у вас достаточно столбцов, ожидаемых для каждой строки, тогда выполните процесс.
Если нет, прочитайте следующую строку и запишите оставшиеся столбцы, пока не получите то, что вам нужно.
Повторить.

Ответ 11

В каждой строке может использоваться несколько простое регулярное выражение. Когда он совпадает, вы обрабатываете каждое поле из совпадения. Когда он не находит совпадения, вы пропускаете эту строку.

Регулярное выражение может выглядеть примерно так.

Match match = Regex.Match(line, @"^(?:,?(?<q>['"](?<field>.*?\k'q')|(?<field>[^,]*))+$");
if (match.Success)
{
  foreach (var capture in match.Groups["field"].Captures)
  {
    string fieldValue = capture.Value;
    // Use the value.
  }
}

Ответ 12

Решение LINQy:

string csvText = File.ReadAllText("C:\\Test.txt");

var query = csvText
    .Replace(Environment.NewLine, string.Empty)
    .Replace("\"\"", "\",\"").Split(',')
    .Select((i, n) => new { i, n }).GroupBy(a => a.n / 3);

Ответ 13

Посмотрите Библиотека FileHelpers Он поддерживает чтение/запись CSV с разрывами строк, а также чтение\запись в excel