Как определить разделитель в строке в PHP? - PullRequest
3 голосов
/ 29 октября 2010

Мне любопытно, если у вас есть строка, как бы вы обнаружили разделитель?

Мы знаем, что php может разбить строку с помощью explode (), для которой требуется параметр разделителя.

А как насчет метода определения разделителя перед отправкой его функции разнесения?

Сейчас я просто выводю строку для пользователя, и он вводит разделитель.Это нормально, но я ищу приложение для распознавания образов для меня.

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

РЕДАКТИРОВАТЬ: я не смогпервоначально указать, что существует вероятный ожидаемый набор разделителей.Любой разделитель, который, вероятно, используется в CSV.Таким образом, технически любой может использовать любой символ для разделения файла CSV, но более вероятно использовать один из следующих символов: запятая, точка с запятой, вертикальная черта и пробел.

РЕДАКТИРОВАТЬ 2: Вот работоспособное решение Iпридумал «решительный разделитель».

$get_images = "86236058.jpg 86236134.jpg 86236134.jpg";

    //Detection of delimiter of image filenames.
        $probable_delimiters = array(",", " ", "|", ";");

        $delimiter_count_array = array(); 

        foreach ($probable_delimiters as $probable_delimiter) {

            $probable_delimiter_count = substr_count($get_images, $probable_delimiter);
            $delimiter_count_array[$probable_delimiter] = $probable_delimiter_count;

        }

        $max_value = max($delimiter_count_array);
        $determined_delimiter_array = array_keys($delimiter_count_array, max($delimiter_count_array));

        while( $element = each( $determined_delimiter_array ) ){
        $determined_delimiter_count = $element['key'];
        $determined_delimiter = $element['value'];
        }

        $images = explode("{$determined_delimiter}", $get_images);

Ответы [ 5 ]

8 голосов
/ 29 октября 2010

Определите, какие разделители вы считаете вероятными (например, ,, ; и |) и для каждого поиска, как часто они встречаются в строке (substr_count).Затем выберите тот, который встречается чаще всего, в качестве разделителя и explode.

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

4 голосов
/ 20 марта 2014

Я бы сказал, что это работает в 99,99% случаев :) Основная идея заключается в том, что количество допустимых разделителей должно быть одинаковым построчно.Этот скрипт вычисляет расхождения в количестве разделителей между всеми строками.Меньшее расхождение означает более вероятный действительный разделитель.

Собрав все это вместе, эта функция считывает строки и возвращает их обратно в виде массива:

function readCSV($fileName)
{
    //detect these delimeters
    $delA = array(";", ",", "|", "\t");
    $linesA = array();
    $resultA = array();

    $maxLines = 20; //maximum lines to parse for detection, this can be higher for more precision
    $lines = count(file($fileName));
    if ($lines < $maxLines) {//if lines are less than the given maximum
        $maxLines = $lines;
    }

    //load lines
    foreach ($delA as $key => $del) {
        $rowNum = 0;
        if (($handle = fopen($fileName, "r")) !== false) {
            $linesA[$key] = array();
            while ((($data = fgetcsv($handle, 1000, $del)) !== false) && ($rowNum < $maxLines)) {
                $linesA[$key][] = count($data);
                $rowNum++;
            }

            fclose($handle);
        }
    }

    //count rows delimiter number discrepancy from each other
    foreach ($delA as $key => $del) {
        echo 'try for key=' . $key . ' delimeter=' . $del;
        $discr = 0;
        foreach ($linesA[$key] as $actNum) {
            if ($actNum == 1) {
                $resultA[$key] = 65535; //there is only one column with this delimeter in this line, so this is not our delimiter, set this discrepancy to high
                break;
            }

            foreach ($linesA[$key] as $actNum2) {
                $discr += abs($actNum - $actNum2);
            }

            //if its the real delimeter this result should the nearest to 0
            //because in the ideal (errorless) case all lines have same column number
            $resultA[$key] = $discr;
        }
    }

    var_dump($resultA);

    //select the discrepancy nearest to 0, this would be our delimiter
    $delRes = 65535;
    foreach ($resultA as $key => $res) {
        if ($res < $delRes) {
            $delRes = $res;
            $delKey = $key;
        }
    }

    $delimeter = $delA[$delKey];

    echo '$delimeter=' . $delimeter;

    //get rows
    $row = 0;
    $rowsA = array();
    if (($handle = fopen($fileName, "r")) !== false) {
        while (($data = fgetcsv($handle, 1000, $delimeter)) !== false) {
            $rowsA[$row] = Array();
            $num = count($data);
            for ($c = 0; $c < $num; $c++) {
                $rowsA[$row][] = trim($data[$c]);
            }
            $row++;
        }
        fclose($handle);
    }

    return $rowsA;
}
2 голосов
/ 12 октября 2012

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

protected function detectDelimiter() {
    $handle = @fopen($this->CSVFile, "r");
    if ($handle) {
        $line=fgets($handle, 4096);
        fclose($handle);            

        $test=explode(',', $line);
        if (count($test)>1) return ',';

        $test=explode(';', $line);
        if (count($test)>1) return ';';

        //.. and so on
    }
    //return default delimiter
    return $this->delimiter;
}
0 голосов
/ 27 января 2015

У меня та же проблема. Моя система будет получать CSV-файлы от клиента, но она может использовать «;», «,» или «» в качестве разделителя, и я хочу улучшить систему, чтобы клиенту не приходилось знать, что это такое (они никогда не делают).

Я ищу и нашел эту библиотеку: https://github.com/parsecsv/parsecsv-for-php

Очень хороший и простой в использовании.

0 голосов
/ 22 августа 2013

Я сделал что-то вроде этого:

$line = fgetcsv($handle, 1000, "|");
if (isset($line[1]))
    {
    echo "delimiter is: |";
    $delimiter="|";
    }
    else
    {
    $line1 = fgetcsv($handle, 1000, ";");
    if (isset($line1[1]))
        {
        echo "delimiter is: ;";
        $delimiter=";";
        }
        else
        {
        echo "delimiter is: ,";
        $delimiter=",";
        }
    }

Это просто проверяет, есть ли второй столбец после чтения строки.

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