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

как узнать, являются ли поля CSV-файла разделителями табуляции или запятыми.Мне нужна проверка php для этого.Может кто-нибудь, пожалуйста, помогите.Заранее спасибо.

Ответы [ 15 ]

24 голосов
/ 12 мая 2014

Слишком поздно ответить на этот вопрос, но надеюсь, что это кому-нибудь поможет.

Вот простая функция, которая будет возвращать разделитель файла.

function getFileDelimiter($file, $checkLines = 2){
        $file = new SplFileObject($file);
        $delimiters = array(
          ',',
          '\t',
          ';',
          '|',
          ':'
        );
        $results = array();
        $i = 0;
         while($file->valid() && $i <= $checkLines){
            $line = $file->fgets();
            foreach ($delimiters as $delimiter){
                $regExp = '/['.$delimiter.']/';
                $fields = preg_split($regExp, $line);
                if(count($fields) > 1){
                    if(!empty($results[$delimiter])){
                        $results[$delimiter]++;
                    } else {
                        $results[$delimiter] = 1;
                    }   
                }
            }
           $i++;
        }
        $results = array_keys($results, max($results));
        return $results[0];
    }

Используйте эту функцию, как показано ниже:

$delimiter = getFileDelimiter('abc.csv'); //Check 2 lines to determine the delimiter
$delimiter = getFileDelimiter('abc.csv', 5); //Check 5 lines to determine the delimiter

PS У меня естьиспользовал preg_split () вместо explode (), потому что explode ('\ t', $ value) не даст правильных результатов.

UPDATE: Спасибо за @RichardEB, указывающую на ошибку в коде.Я обновил это сейчас.

11 голосов
/ 11 мая 2013

Вот что я делаю.

  1. Анализ первых 5 строк файла CSV
  2. Подсчитать количество разделителей [запятых, табуляции, точек с запятой и двоеточий] в каждой строке
  3. Сравните количество разделителей в каждой строке. Если у вас правильно отформатированный CSV, то в каждой строке будет совпадать одно из разделителей.

Это не будет работать в 100% случаев, но это хорошая отправная точка. Как минимум, это уменьшит количество возможных разделителей (что облегчит пользователям выбор правильного разделителя).

/* Rearrange this array to change the search priority of delimiters */
$delimiters = array('tab'       => "\t",
                'comma'     => ",",
                'semicolon' => ";"
                );

$handle = file( $file );    # Grabs the CSV file, loads into array

$line = array();            # Stores the count of delimiters in each row

$valid_delimiter = array(); # Stores Valid Delimiters

# Count the number of Delimiters in Each Row
for ( $i = 1; $i < 6; $i++ ){
foreach ( $delimiters as $key => $value ){
    $line[$key][$i] = count( explode( $value, $handle[$i] ) ) - 1;
}
}


# Compare the Count of Delimiters in Each line
foreach ( $line as $delimiter => $count ){

# Check that the first two values are not 0
if ( $count[1] > 0 and $count[2] > 0 ){
    $match = true;

    $prev_value = '';
    foreach ( $count as $value ){

        if ( $prev_value != '' )
            $match = ( $prev_value == $value and $match == true ) ? true : false;

        $prev_value = $value;
    }

} else { 
    $match = false;
}

if ( $match == true )    $valid_delimiter[] = $delimiter;

}//foreach

# Set Default delimiter to comma
$delimiter = ( $valid_delimiter[0] != '' ) ? $valid_delimiter[0] : "comma";


/*  !!!! This is good enough for my needs since I have the priority set to "tab"
!!!! but you will want to have to user select from the delimiters in $valid_delimiter
!!!! if multiple dilimiter counts match
*/

# The Delimiter for the CSV
echo $delimiters[$delimiter]; 
8 голосов
/ 03 августа 2010

Нет 100% надежного способа определить это. Что вы можете сделать, это

  • Если у вас есть метод для проверки полей, которые вы прочитали, попробуйте прочитать несколько полей, используя любой из разделителей, и проверьте их по вашему методу. Если он сломается, используйте другой.
  • Подсчет появления вкладок или запятых в файле. Обычно один значительно выше другого
  • Последнее, но не менее важное: спросите пользователя и дайте ему возможность переопределить ваши догадки.
4 голосов
/ 09 сентября 2013

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

//The delimiters array to look through
$delimiters = array(
    'semicolon' => ";",
    'tab'       => "\t",
    'comma'     => ",",
);

//Load the csv file into a string
$csv = file_get_contents($file);
foreach ($delimiters as $key => $delim) {
    $res[$key] = substr_count($csv, $delim);
}

//reverse sort the values, so the [0] element has the most occured delimiter
arsort($res);

reset($res);
$first_key = key($res);

return $delimiters[$first_key]; 
3 голосов
/ 08 ноября 2012

В моей ситуации пользователи предоставляют CSV-файлы, которые затем вводятся в базу данных SQL. Они могут сохранить электронную таблицу Excel в виде файлов с запятыми или табуляцией. Программа, преобразующая электронную таблицу в SQL, должна автоматически определять, являются ли поля разделенными табуляцией или запятыми

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

1 голос
/ 08 марта 2017

Я использовал решение @Jay Bhatt для определения разделителя файла csv, но он не работал для меня, поэтому я применил несколько исправлений и комментариев, чтобы процесс был более понятным.

Смотрите мою версию функции @Jay Bhatt:

function decide_csv_delimiter($file, $checkLines = 10) {

    // use php's built in file parser class for validating the csv or txt file
    $file = new SplFileObject($file);

    // array of predefined delimiters. Add any more delimiters if you wish
    $delimiters = array(',', '\t', ';', '|', ':');

    // store all the occurences of each delimiter in an associative array
    $number_of_delimiter_occurences = array();

    $results = array();

    $i = 0; // using 'i' for counting the number of actual row parsed
    while ($file->valid() && $i <= $checkLines) {

        $line = $file->fgets();

        foreach ($delimiters as $idx => $delimiter){

            $regExp = '/['.$delimiter.']/';
            $fields = preg_split($regExp, $line);

            // construct the array with all the keys as the delimiters
            // and the values as the number of delimiter occurences
            $number_of_delimiter_occurences[$delimiter] = count($fields);

        }

       $i++;
    }

    // get key of the largest value from the array (comapring only the array values)
    // in our case, the array keys are the delimiters
    $results = array_keys($number_of_delimiter_occurences, max($number_of_delimiter_occurences));


    // in case the delimiter happens to be a 'tab' character ('\t'), return it in double quotes
    // otherwise when using as delimiter it will give an error,
    // because it is not recognised as a special character for 'tab' key,
    // it shows up like a simple string composed of '\' and 't' characters, which is not accepted when parsing csv files
    return $results[0] == '\t' ? "\t" : $results[0];
}

Я лично использую эту функцию, чтобы помочь автоматически разобрать файл с PHPExcel , и она работает красиво и быстро.

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

ПРИМЕЧАНИЕ: Это всего лишь модифицированная версия решения @Jay Bhatt для этого вопроса. Все кредиты отправляются @Jay Bhatt.

0 голосов
/ 31 мая 2018

вы можете просто использовать fgetcsv (); Собственная функция PHP следующим образом:

function getCsvDelimeter($file)
{
    if (($handle = fopen($file, "r")) !== FALSE) {
        $delimiters = array(',', ';', '|', ':'); //Put all that need check

        foreach ($delimiters AS $item) {
            //fgetcsv() return array with unique index if not found the delimiter
            if (count(fgetcsv($handle, 0, $item, '"')) > 1) {
                $delimiter = $item;

                break;
            }
        }
    }

    return (isset($delimiter) ? $delimiter : null);
}
0 голосов
/ 06 марта 2015

Если у вас очень большой пример файла в ГБ, поместите первые несколько строк во временный файл.Откройте временный файл в vi

head test.txt > te1
vi te1
0 голосов
/ 10 января 2015

Как насчет чего-то простого?

function findDelimiter($filePath, $limitLines = 5){
    $file = new SplFileObject($filePath);
    $delims = $file->getCsvControl();
    return $delims[0];
}
0 голосов
/ 17 ноября 2014

Спасибо за все ваши входы, я сделал мой, используя ваши трюки: preg_split, fgetcsv, loop и т. Д.

Но я реализовал нечто, чего на удивление не было здесь, использование fgets вместо чтения всего файлалучше, если файл тяжелый!

Вот код:

ini_set("auto_detect_line_endings", true);
function guessCsvDelimiter($filePath, $limitLines = 5) {
    if (!is_readable($filePath) || !is_file($filePath)) {
        return false;
    }

    $delimiters = array(
        'tab'       => "\t",
        'comma'     => ",",
        'semicolon' => ";"
    );

    $fp = fopen($filePath, 'r', false);
    $lineResults = array(
        'tab'       => array(),
        'comma'     => array(),
        'semicolon' => array()
    );

    $lineIndex = 0;
    while (!feof($fp)) {
        $line = fgets($fp);

        foreach ($delimiters as $key=>$delimiter) {
            $lineResults[$key][$lineIndex] = count (fgetcsv($fp, 1024, $delimiter)) - 1;
        }

        $lineIndex++;
        if ($lineIndex > $limitLines) break;
    }
    fclose($fp);

    // Calculating average
    foreach ($lineResults as $key=>$entry) {
        $lineResults[$key] = array_sum($entry)/count($entry);
    }

    arsort($lineResults);
    reset($lineResults);
    return ($lineResults[0] !== $lineResults[1]) ? $delimiters[key($lineResults)] : $delimiters['comma'];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...