Как программно угадать, является ли файл CSV запятой или точкой с запятой - PullRequest
12 голосов
/ 07 мая 2010

В большинстве случаев файлы CSV представляют собой текстовые файлы с записями, разделенными запятыми. Тем не менее, иногда эти файлы будут разделены точкой с запятой. (Excel будет использовать точки с запятой при сохранении CSV, если в региональных настройках десятичный разделитель установлен в качестве запятой - это распространено в Европе. Ссылка: http://en.wikipedia.org/wiki/Comma-separated_values#Application_support)

У меня вопрос: как лучше всего угадать программе, стоит ли разделять ее запятыми или точками с запятой?

например. линия как 1,1; 1,1 может быть неоднозначной. Это может быть интерпретировано как запятая: 1 1; 1 (строка) 1

или точка с запятой, разделенная как 1,1 1,1

Мое лучшее предположение пока что состоит в том, чтобы попытаться разобрать файл и с, и; разделители, затем выберите синтаксический анализ, который имеет наибольшее количество строк той же длины, что и первая строка (обычно строка заголовка). Если у обоих одинаковое количество строк, выберите тот, у которого больше столбцов. Основным недостатком этого является дополнительные накладные расходы.

Мысли

Ответы [ 4 ]

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

Если в каждой строке должно быть одинаковое количество столбцов, что, как я полагаю, имеет место в Excel, то, используя запятые и точки с запятой, определите количество столбцов для строк N и N + 1.Какой бы метод (запятые или точки с запятой) выдает другой ответ, он неверен (не формат файла).Вы можете начать с самого начала, и вам нужно только идти, пока один из них не окажется неверным.Вам не нужны строки заголовка или что-нибудь.Вам не нужно читать больше файла, чем необходимо, и он никогда не сможет дать вам неправильный ответ для формата файла, он может просто дойти до конца и еще не прийти к выводу.Все, что вам нужно, - чтобы каждая строка имела одинаковое количество столбцов для хранения.

1 голос
/ 15 декабря 2011

Вы можете прочитать первую строку

FileReader fileReader = new FileReader(filePath);
    BufferedReader bufferedReader = new BufferedReader(fileReader);
    String s = bufferedReader.readLine();
    String substring = s.substring(s.indexOf(firstColumnName) + 3, s.indexOf(firstColumnName) + 4);
    bufferedReader.close();
    fileReader.close();
    substring.charAt(0);

Затем вы фиксируете это значение

substring.charAt (0)

в зависимости от того, является ли CSV запятой или точкой с запятой, можно использовать последнее значение

1 голос
/ 07 мая 2010

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

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

0 голосов
/ 14 января 2014

Это мой код (без проверки текста) ... возможно, это может помочь или создать базу :-)!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using MoreLinq; // http://stackoverflow.com/questions/15265588/how-to-find-item-with-max-value-using-linq

namespace HQ.Util.General.CSV
{
    public class CsvHelper
    {
        public static Dictionary<LineSeparator, Func<string, string[]>>  DictionaryOfLineSeparatorAndItsFunc = new Dictionary<LineSeparator, Func<string, string[]>>();

        static CsvHelper()
        {
            DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Unknown] = ParseLineNotSeparated;
            DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Tab] = ParseLineTabSeparated;
            DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Semicolon] = ParseLineSemicolonSeparated;
            DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Comma] = ParseLineCommaSeparated;
        }

        // ******************************************************************
        public enum LineSeparator
        {
            Unknown = 0,
            Tab,
            Semicolon,
            Comma
        }

        // ******************************************************************
        public static LineSeparator GuessCsvSeparator(string oneLine)
        {
            List<Tuple<LineSeparator, int>> listOfLineSeparatorAndThereFirstLineSeparatedValueCount = new List<Tuple<LineSeparator, int>>();

            listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Tab, CsvHelper.ParseLineTabSeparated(oneLine).Count()));
            listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Semicolon, CsvHelper.ParseLineSemicolonSeparated(oneLine).Count()));
            listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Comma, CsvHelper.ParseLineCommaSeparated(oneLine).Count()));

            Tuple<LineSeparator, int> bestBet = listOfLineSeparatorAndThereFirstLineSeparatedValueCount.MaxBy((n)=>n.Item2);

            if (bestBet != null && bestBet.Item2 > 1)
            {
                return bestBet.Item1;
            }

            return LineSeparator.Unknown;
        }

        // ******************************************************************
        public static string[] ParseLineCommaSeparated(string line)
        {
            // CSV line parsing : From "jgr4" in http://www.kimgentes.com/worshiptech-web-tools-page/2008/10/14/regex-pattern-for-parsing-csv-files-with-embedded-commas-dou.html
            var matches = Regex.Matches(line, @"\s?((?<x>(?=[,]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^,]+)),?",
                                        RegexOptions.ExplicitCapture);

            string[] values = (from Match m in matches
                               select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();

            return values;
        }

        // ******************************************************************
        public static string[] ParseLineTabSeparated(string line)
        {
            var matchesTab = Regex.Matches(line, @"\s?((?<x>(?=[\t]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^\t]+))\t?",
                            RegexOptions.ExplicitCapture);

            string[] values = (from Match m in matchesTab
                                select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();

            return values;
        }

        // ******************************************************************
        public static string[] ParseLineSemicolonSeparated(string line)
        {
            // CSV line parsing : From "jgr4" in http://www.kimgentes.com/worshiptech-web-tools-page/2008/10/14/regex-pattern-for-parsing-csv-files-with-embedded-commas-dou.html
            var matches = Regex.Matches(line, @"\s?((?<x>(?=[;]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^;]+));?",
                                        RegexOptions.ExplicitCapture);

            string[] values = (from Match m in matches
                               select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();

            return values;
        }

        // ******************************************************************
        public static string[] ParseLineNotSeparated(string line)
        {
            string [] lineValues = new string[1];
            lineValues[0] = line;
            return lineValues;
        }

        // ******************************************************************
        public static List<string[]> ParseText(string text)
        {
            string[] lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            return ParseString(lines);
        }

        // ******************************************************************
        public static List<string[]> ParseString(string[] lines)
        {
            List<string[]> result = new List<string[]>();

            LineSeparator lineSeparator = LineSeparator.Unknown;
            if (lines.Any())
            {
                lineSeparator = GuessCsvSeparator(lines[0]);
            }

            Func<string, string[]> funcParse = DictionaryOfLineSeparatorAndItsFunc[lineSeparator];

            foreach (string line in lines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                result.Add(funcParse(line));
            }

            return result;
        }

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