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

Как определить, какой разделитель используется в текстовом файле?

Мне нужно проанализировать файлы CSV и TSV. Я не могу полагаться на пользователей, чтобы узнать разницу, поэтому я хотел бы не просить пользователя выбрать тип. Есть ли простой способ определить, какой разделитель используется?

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

Изменить: Другим интересным аспектом этого проекта является то, что мне также нужно будет обнаружить схему файла, когда я его прочитаю, потому что он может быть одним из многих. Это означает, что я не буду знать, сколько полей у меня есть, пока я не смогу его разобрать.

4b9b3361

Ответ 1

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

Тогда вы могли бы просто догадаться относительно разделителя, чтобы начать (например, сначала запятая или вкладка).

Ответ 2

В Python существует класс Sniffer в модуле csv, который может использоваться для угадывания заданного разделителя файлов и символов кавычек. Его стратегия (цитируется из csv.py docstrings):


[Во-первых, посмотрите] текст, заключенный между двумя идентичными кавычками (вероятный катчар), которым предшествуют и следуют по тому же характеру (вероятный разделитель). Например:

         ,'some text',

Цитата с наибольшим выигрышем, то же самое с разделителем. Если нет цитаты, разделитель не может быть определен таким образом.

В этом случае попробуйте выполнить следующее:

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

  • построить таблицу частоты каждый символ в каждой строке.
  • постройте таблицу частот этого частота (метачастота?), например. x произошло 5 раз в 10 рядах, 6 раз в 1000 строк, 7 раз в 2 строки
  • используйте режим метачастоты для определения ожидаемого частота для этого символа
  • узнать, как часто персонаж фактически соответствует этой цели.
  • персонаж, который лучше всего соответствует его Цель - разделитель.

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


Я не буду приводить здесь исходный код - он находится в каталоге Lib каждой установки Python.

Помните, что CSV также может использовать точки с запятой вместо запятых как разделители (например, в немецких версиях Excel, CSV разделены точкой с запятой, потому что запятые используются в качестве разделителей десятичных чисел в Германии...)

Ответ 3

Знаете ли вы, сколько полей должно присутствовать в строке? Если это так, я бы прочитал первые несколько строк файла и проверил на основании этого.

По моему опыту, "обычные" данные довольно часто содержат запятые, но редко содержат символы табуляции. Это предполагает, что вы должны проверять количество последовательных вкладок в первых нескольких строках и идти с этим выбором в качестве предпочтительного предположения. Конечно, это зависит от того, какие данные у вас есть.

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

Ответ 4

Это в PHP, но это кажется довольно надежным:

$csv = 'something;something;something
someotherthing;someotherthing;someotherthing
';
$candidates = array(',', ';', "\t");
$csvlines = explode("\n", $csv);
foreach ($candidates as $candidatekey => $candidate) {
 $lastcnt = 0;
 foreach ($csvlines as $csvline) {
  if (strlen($csvline) <= 2) continue;
  $thiscnt = substr_count($csvline, $candidate);
  if (($thiscnt == 0) || ($thiscnt != $lastcnt) && ($lastcnt != 0)) {
   unset($candidates[$candidatekey]);
   break;
  }
  $lastcnt = $thiscnt;
 }
}
$delim = array_shift($candidates);
echo $delim;

Что он делает, так это: Для каждого указанного возможного разделителя он считывает каждую строку в CSV и проверяет, является ли количество раз, когда происходит каждый разделитель, является постоянным. Если нет, отделитель-кандидат удаляется и, в конечном итоге, вы должны иметь один разделитель.

Ответ 5

Я бы предположил, что ваше предлагаемое решение будет лучшим способом. В хорошо сформированном файле CSV или TSV количество запятых или вкладок соответственно на строку должно быть постоянным (без изменений вообще). Делайте подсчет каждого для каждой строки файла и проверяйте, какая из них является постоянной для всех строк. Казалось бы, маловероятно, что количество обоих разделителей для каждой строки идентично, но в этом, по-видимому, редком случае вы можете, конечно, запросить пользователя.

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

Ответ 6

Просто прочитайте несколько строк, подсчитайте количество запятых и количество вкладок и сравните их. Если там 20 запятых и нет вкладок, это в CSV. Если имеется 20 вкладок и 2 запятых (возможно, в данных), это в TSV.

Ответ 7

Я столкнулся с подобной потребностью и подумал, что поделюсь тем, что я придумал. Я еще не запускал много данных, так что возможны возможные краевые случаи. Кроме того, имейте в виду, что цель этой функции не является на 100% достоверностью разделителя, но лучше всего предположить, что она будет представлена ​​пользователю.

/// <summary>
/// Analyze the given lines of text and try to determine the correct delimiter used. If multiple
/// candidate delimiters are found, the highest frequency delimiter will be returned.
/// </summary>
/// <example>
/// string discoveredDelimiter = DetectDelimiter(dataLines, new char[] { '\t', '|', ',', ':', ';' });
/// </example>
/// <param name="lines">Lines to inspect</param>
/// <param name="delimiters">Delimiters to search for</param>
/// <returns>The most probable delimiter by usage, or null if none found.</returns>
public string DetectDelimiter(IEnumerable<string> lines, IEnumerable<char> delimiters) {
  Dictionary<char, int> delimFrequency = new Dictionary<char, int>();

  // Setup our frequency tracker for given delimiters
  delimiters.ToList().ForEach(curDelim => 
    delimFrequency.Add(curDelim, 0)
  );

  // Get a total sum of all occurrences of each delimiter in the given lines
  delimFrequency.ToList().ForEach(curDelim => 
    delimFrequency[curDelim.Key] = lines.Sum(line => line.Count(p => p == curDelim.Key))
  );

  // Find delimiters that have a frequency evenly divisible by the number of lines
  // (correct & consistent usage) and order them by largest frequency
  var possibleDelimiters = delimFrequency
                    .Where(f => f.Value > 0 && f.Value % lines.Count() == 0)
                    .OrderByDescending(f => f.Value)
                    .ToList();

  // If more than one possible delimiter found, return the most used one
  if (possibleDelimiters.Any()) {
    return possibleDelimiters.First().Key.ToString();
  }
  else {
    return null;
  }   

}

Ответ 8

Нет "эффективного" способа.

Ответ 9

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

Ответ 10

По моему опыту, данные редко содержат вкладки, поэтому строка полей с разделителями табуляции (как правило) будет достаточно очевидной.

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

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

Ответ 11

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

Ответ 12

Предполагая, что у вас есть стандартный набор столбцов, который вы ожидаете...

Я бы использовал FileHelper (проект с открытым исходным кодом на SourceForge). http://filehelpers.sourceforge.net/

Определите два шаблона для чтения, один для комы, один для вкладок.

Если первый не удался, попробуйте второй.

Ответ 13

Вы можете проверить, использует ли строка один разделитель, например:

while ((line = readFile.ReadLine()) != null)
{
    if (line.Split('\t').Length > line.Split(',').Length) // tab delimited or comma delimited?
        row = line.Split('\t');
    else
        row = line.Split(',');

    parsedData.Add(row);
}