2011-12-02 29 views
19

Tengo valores csv como esto:str_getcsv en una matriz multidimensional en php

$csv_data = "test,this,thing 
      hi,there,this 
      is,cool,dude 
      have,fun"; 

quiero tomar una cadena CSV entero y leerlo en una matriz multidemensional modo que me sale:

array(
    array(
     'test' => 'hi', 
     'this' => 'there', 
     'thing' => 'this' 
    ), 
    array(
     'test' => 'is', 
     'this' => 'cool', 
     'thing' => 'dude' 
    ), 
    array(
     'test' => 'have', 
     'this' => 'fun', 
     'thing' => '' 
    ) 
); 

Quiero un resultado como ese, tenga en cuenta que el valor de CSV es dinámico.

+0

¿Debería la última línea de los datos CSV tener otra coma? No parece datos de CSV válidos si las filas no tienen todas la misma cantidad de columnas. ¿O el código necesita tener en cuenta ese número variable de columnas? – Wiseguy

+0

es como, la primera fila sería las teclas de una matriz y luego otras su valor. en la parte 'cosa' => ', eso es correcto. – PinoyStackOverflower

+0

Lo entiendo, pero la última línea de datos CSV es 'have, fun', que solo tiene dos columnas, no tres como las otras líneas. ¿Necesitamos dar cuenta de las filas que tienen una cantidad incorrecta de columnas como esa? – Wiseguy

Respuesta

33

Suponiendo que todas las filas de los datos CSV tiene el mismo número de columnas, esto debería funcionar.

$lines = explode("\n", $csv_data); 
$head = str_getcsv(array_shift($lines)); 

$array = array(); 
foreach ($lines as $line) { 
    $array[] = array_combine($head, str_getcsv($line)); 
} 

Si las líneas tienen un número variable de columnas (como en el ejemplo, donde la última línea tiene 2 columnas en lugar de 3), utilice este bucle en su lugar:

foreach ($lines as $line) { 
    $row = array_pad(str_getcsv($line), count($head), ''); 
    $array[] = array_combine($head, $row); 
} 
+1

¿Y qué pasa con los datos de csv que contienen \ n en campos individuales? La notación habitual en csv es encerrar dichos campos con comillas, p. "algún valor \ nin un campo". Entonces, esos \ n tienen que ser ignorados durante el análisis. Su enfoque de explosión los cortará. –

+0

@ChrisPillen Aunque no es uno de los requisitos del solicitante, ese es un punto válido. ¿Cuál crees que sería el mejor remedio para eso? Guarde los datos CSV en un ['tmpfile()'] (http://php.net/tmpfile) y analícelos usando ['fgetcsv()'] (http://php.net/fgetcsv)? ¿Debo agregar un ejemplo de eso a mi respuesta? – Wiseguy

+0

@Wiseguy Puede usar regex para analizar los datos, pero usar un archivo temporal y 'fgetcsv()' sería más simple y mucho más limpio. –

4

Aquí es una solución completa:

$lines = explode("\n", $csv_data); 
$formatting = explode(",", $lines[0]); 
unset($lines[0]); 
$results = array(); 
foreach ($lines as $line) { 
    $parsedLine = str_getcsv($line, ','); 
    $result = array(); 
    foreach ($formatting as $index => $caption) { 
     if(isset($parsedLine[$index])) { 
     $result[$formatting[$index]] = trim($parsedLine[$index]); 
     } else { 
     $result[$formatting[$index]] = ''; 
     } 
    } 
    $results[] = $result; 
} 

Entonces, ¿qué estamos haciendo aquí?

  • En primer lugar, los datos CSV se divide en serie de líneas con explode
  • Puesto que la primera fila en su CSV describe el formato de datos, que debe ser separado de las filas de datos reales (explode y unset)
  • Para almacenar los resultados, inicializamos una nueva matriz ($results)
  • Foreach se usa para recorrer los datos línea por línea. Para cada línea:
    • línea se analiza con str_getcsv
    • Un conjunto de resultados vacío de PHP es inicializado
    • Cada línea es inspeccionado a la luz del formato. Se agregan celdas y las columnas faltantes se rellenan con cadenas vacías.
+0

No está produciendo correctamente lo que deseaba, gracias \ por su respuesta :) – PinoyStackOverflower

+0

Era un problema mucho más complejo, pensé. Verifique la respuesta revisada. La explicación detallada seguirá. – jsalonen

+0

Explicación agregada. Dada su descripción, esto debería responder la pregunta. – jsalonen

2

Aquí está una solución muy simple y limpia:

function parse_row($row) { 
    return array_map('trim', explode(',', $row)); 
} 

$rows = str_getcsv($csv_data, "\n"); 
$keys = parse_row(array_shift($rows)); 
$result = array(); 

foreach ($rows as $row) { 
    $row = parse_row($row); 
    $row = array_pad($row, 3, NULL); 

    $result[] = array_combine($keys, $row); 
} 
Cuestiones relacionadas