PHP Проверка метода: могу ли я проанализировать CSV с помощью только разнесения и str_replace - PullRequest
2 голосов
/ 31 января 2020

Вчера я собрал парсер, который получает однострочные входные данные из функции file () PHP и разбирает каждую строку на поля (код показан ниже). Я использую file () вместо fopen (), чтобы не блокировать файлы, о которых идет речь.

Я рассматриваю другие решения и натолкнулся на комментарий greg.kindel к этому сообщению о том, что любое решение, использующее сплиты или сопоставление с шаблоном обречено на неудачу: Javascript код для анализа данных CSV

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

Код:

function read_csv($fname = '', $use_headers = true)
{
    if(strlen($fname) >= 5 && substr($fname, strlen($fname)-4, 4) == '.csv')
    {
        $data_array = array();
        $headers = array();

        # Parse file into individual rows
        # Iterate through rows to parse fields.
        $rows = file($fname);
        for($i = 0; $i < count($rows); $i++)
        {
            # Remove non-printable characters
            # Split string by commas
            $rows[$i] = preg_replace('/[[:^print:]]/', '', $rows[$i]);

            $split = explode(',', $rows[$i]);
            $text = array();
            $count = 0;
            $fields = array();

            # Iterate through split string
            foreach($split as $key => $value)
            {
                # Count cumulative number of quotation marks
                # Build field string
                # When cumulative number of quotation marks is even, save string and start new field
                $count += strlen($value) - strlen(str_replace('"', '', $value));
                $text[] = $value;
                if($count % 2 == 0)
                {
                    # Reinsert commas in string
                    # Remove escape quotes from fields encapsulated by quotes
                    # Convert double-quotation marks to single
                    $result = implode(',', $text);
                    if(substr($result, 0, 1) == '"')
                        {$result = str_replace('""', '"', substr($result, 1, strlen($result)-2));}
                    $fields[] = $result;
                    $count = 0;
                    $text = array();
                }
            }

            # Write $fields to associative array, headers optional
            if($i == 0 && $use_headers)
            {
                foreach($fields as $key => $header)
                    {$headers[$key] = $header;}
            } else {
                $tmp = array();
                foreach($fields as $key => $value)
                {
                    if($use_headers)
                        {$tmp[$headers[$key]] = $value;} 
                    else
                        {$tmp[] = $value;}
                }
                $data_array[] = $tmp;
            }
        }
        return $data_array;
    } else {
        # If provided filename is not a csv file, return an error
        # Uses the same associative array format as $data_array
        return array(0 => array('Error' => 'Invalid filename', 'Filename' => $fname));
    }
}
...