Простой CSV-ридер? - PullRequest
       4

Простой CSV-ридер?

1 голос
/ 24 августа 2010

все

Я начал с того, что, как я думал, будет довольно простой задачей. (преобразовать csv в формат "wiki"), но я столкнулся с несколькими трудностями, с которыми у меня возникают проблемы при работе с

У меня 3 основные проблемы

1) некоторые ячейки содержат \ r \ n (поэтому при чтении построчно каждая новая строка обрабатывается как новая ячейка

2) некоторые строки содержат "," (я попытался переключиться на \ t удаленные файлы, но у меня все еще возникает проблема с выходом, когда между двумя "") *

3) некоторые строки полностью пустые, за исключением разделителя ("," или "\ t"), другие неполные (это нормально, мне просто нужно убедиться, что ячейка находится в правильном месте)

Я пробовал несколько классов для чтения CSV, но они могли бы увеличить число проблем, перечисленных выше

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

пока у меня есть две "попытки, которые не работают

Попытка 1 (не переносит \ r \ n в ячейке)

OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            openFileDialog1.Filter = "tab sep file (*.txt)|*.txt|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if (cb_sortable.Checked)
                {
                    header = "{| class=\"wikitable sortable\" border=\"1\" \r\n|+ Sortable table";
                }

                StringBuilder sb = new StringBuilder();
                string line;
                bool firstline = true;
                StreamReader sr = new StreamReader(openFileDialog1.FileName);

                sb.AppendLine(header);

                while ((line = sr.ReadLine()) != null)
                {

                    if (line.Replace("\t", "").Length > 1)
                    {
                        string[] hold;
                        string lead = "| ";

                        if (firstline && cb_header.Checked == true)
                        {
                            lead = "| align=\"center\" style=\"background:#f0f0f0;\"| ";
                        }

                        hold = line.Split('\t');
                        sb.AppendLine(table);
                        foreach (string row in hold)
                        {
                            sb.AppendLine(lead + row.Replace("\"", ""));
                        }


                        firstline = false;
                    }
                }
                sb.AppendLine(footer);
                Clipboard.SetText(sb.ToString());
                MessageBox.Show("Done!");
        }


        }
        string header = "{| class=\"wikitable\" border=\"1\" ";
        string footer = "|}";
        string table = "|-";

попытка 2 (может обрабатывать \ r \ n, но смещает ячейки над пустыми ячейками) (еще не завершена)

OpenFileDialog openFileDialog1 = новый OpenFileDialog ();

        openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        openFileDialog1.Filter = "txt file (*.txt)|*.txt|All files (*.*)|*.*";
        openFileDialog1.FilterIndex = 1;
        openFileDialog1.RestoreDirectory = true;

        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            if (cb_sortable.Checked)
            {
                header = "{| class=\"wikitable sortable\" border=\"1\" \r\n|+ Sortable table";
            }


            using (StreamReader sr = new StreamReader(openFileDialog1.FileName))
            {


                string text = sr.ReadToEnd();
                string[] cells = text.Split('\t');
                int columnCount = 0;
                foreach (string cell in cells)
                {

                    if (cell.Contains("\r\n"))
                    {
                        break;
                    }
                    columnCount++;
                }          


            }

по сути, все, что мне нужно, это "разделить, если не между \" ", но сейчас я просто в растерянности

Любые советы или подсказки будут с благодарностью

Ответы [ 5 ]

3 голосов
/ 24 августа 2010
2 голосов
/ 24 августа 2010

Вы также можете взглянуть на http://www.filehelpers.com/ ...

Не пытайтесь делать это самостоятельно, если вы можете использовать библиотеки!

1 голос
/ 24 сентября 2010

Для спецификации длиной в две страницы формат CSV обманчив в своей простоте. Большинство коротких реализаций парсера, которые можно найти в интернете, являются явно некорректными, так или иначе. Несмотря на это, формат вряд ли требует реализации 1k + SLOC.

public static class CsvImport {
    /// <summary>
    /// Parse a Comma Separated Value (CSV) source into rows of strings. [1]
    /// 
    /// The header row (if present) is not treated specially. No checking is
    /// performed to ensure uniform column lengths among rows. If no input
    /// is available, a single row containing String.Empty is returned. No
    /// support is provided for debugging invalid CSV files. Callers who
    /// desire such assistance are encouraged to use a TextReader that can
    /// report the current line and column position.
    /// 
    /// [1] http://tools.ietf.org/html/rfc4180
    /// </summary>
    public static IEnumerable<string[]> Deserialize(TextReader input) {
        if (input.Peek() == Sentinel) yield return new [] { String.Empty };
        while (input.Peek() != Sentinel) {
            // must read in entire row *now* to see if we're at end of input
            yield return DeserializeRow(input).ToArray(); 
        }
    }

    const int Sentinel = -1;
    const char Quote = '"';
    const char Separator = (char)System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator;

    static IEnumerable<string> DeserializeRow(TextReader input) {
        var field = new StringBuilder();
        while (true) {
            var c = input.Read();
            if (c == Separator) {
                yield return field.ToString();
                field = new StringBuilder();
            } else if (c == '\r') {
                if (input.Peek() == '\n') {
                    input.Read();
                }
                yield return field.ToString();
                yield break;
            } else if (new [] { '\n', Sentinel }.Contains(c)) {
                yield return field.ToString();
                yield break;
            } else if (c == Quote) {
                field.Append(DeserializeQuoted(input));
            } else {
                field.Append((char) c);
            }
        }
    }

    static string DeserializeQuoted(TextReader input) {
        var quoted = new StringBuilder();
        while (input.Peek() != Sentinel) {
            var c = input.Read();
            if (c == Quote) {
                if (input.Peek() == Quote) {
                    quoted.Append(Quote);
                    input.Read();
                } else {
                    return quoted.ToString();
                }
            } else {
                quoted.Append((char) c);
            }
        }
        throw new UnexpectedEof("End-of-file inside quoted section.");
    }

    public class UnexpectedEof : Exception {
        public UnexpectedEof(string message) : base(message) { }
    }
}
1 голос
/ 24 августа 2010

Здесь есть достойная реализация ...

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

1 голос
/ 24 августа 2010

Попробуйте взглянуть здесь . Ваш код не выполняет веб-запросов, но в действительности это показывает, как анализировать CSV, возвращаемый веб-службой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...