Вчера я собрал парсер, который получает однострочные входные данные из функции 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));
}
}