2015-05-27 11 views
6

wenn ich explodieren CSV-Datei auf Trennzeichen (;) die in einigen erfolgreich explodieren Excel-Programm und es versäumt, in anderenexplodieren CSV-Datei auf Trennzeichen (;) und Trennzeichen (,)?

auch wenn ich CSV-Datei auf Trennzeichen (,) die Explosion erfolgreich in einige Excel-Programm und es versäumt, explodieren in andere

Wie kann ich in allen Versionen von Excel explodieren? Wie kann ich den perfekten Begrenzer zum Explodieren wissen?

ja, es gibt Code ..

if (!function_exists('create_csv')) { 
    function create_csv($query, &$filename = false, $old_csv = false) { 
     if(!$filename) $filename = "data_export_".date("Y-m-d").".csv"; 
     $ci = &get_instance(); 
     $ci->load->helper('download'); 
     $ci->load->dbutil(); 
     $delimiter = ";"; 
     $newline = "\r\n"; 
     $csv = "Data:".date("Y-m-d").$newline; 
     if($old_csv) 
      $csv .= $old_csv; 
     else 
      $csv .= $ci->dbutil->csv_from_result($query, $delimiter, $newline); 
     $columns = explode($newline, $csv); 
     $titles = explode($delimiter, $columns[1]); 
     $new_titles = array(); 
     foreach ($titles as $item) { 
      array_push($new_titles, lang(trim($item,'"'))); 
     } 
     $columns[1] = implode($delimiter, $new_titles); 
     $csv = implode($newline, $columns); 
     return $csv; 
    } 
} 

manchmal habe ich $ delimiter = ""; und someims $ delimiter = ",";

Dank ..

+2

Sie können nicht. Das Trennzeichen, das jede MS Excel-Instanz verwendet, ist länderspezifisch und basiert in der Regel darauf, ob das Land, für das es konfiguriert ist, ein Dezimaltrennzeichen, oder ein "." Verwendet Es gibt keine universelle Antwort .... wenn es war, müssten Sie nicht einmal fragen –

+0

Es ist ein Grund, warum CSV nicht ein gutes Format ist, um als Alternative zu Excel nativen Formaten zu verwenden –

+0

Haben Sie etwas Code zu zeigen uns? Versuchen Sie, die Datei zu lesen und dann die Zeilen zu explodieren, oder verwenden Sie fgetcsv? – foxbeefly

Antwort

1

können Sie Hilfsfunktion verwenden, um beste Trennzeichen zu erkennen wie:

public function find_delimiter($csv) 
{ 
    $delimiters = array(',', '.', ';'); 
    $bestDelimiter = false; 
    $count = 0; 
    foreach ($delimiters as $delimiter) 
     if (substr_count($csv, $delimiter) > $count) { 
      $count = substr_count($csv, $delimiter); 
      $bestDelimiter = $delimiter; 
     } 
    return $bestDelimiter; 
} 
0

Es gibt keine Art und Weise ist zu 100% sicher zu sein, Sie die realen Trennzeichen ausgerichtet sind. Alles, was Sie tun können, ist zu erraten.

Sie sollten zuerst das richtige Trennzeichen finden und dann die CSV-Datei für dieses Trennzeichen auflösen.

das Trennzeichen zu finden, im Grunde eine Funktion möchten, dass die Anzahl der , und die Anzahl der ; zählt und dass gibt die größer.

Etwas wie:

$array = explode(find_delimiter($csv), $csv); 

Hoffe, es hilft;)

Edit: Ihre find_delimiter Funktion so etwas wie sein könnte:

function find_delimiter($csv) 
{ 
    $arrDelimiters = array(',', '.', ';'); 
    $arrResults = array(); 
    foreach ($arrDelimiters as $delimiter) 
    { 
     $arrResults[$delimiter] = count(explode($delimiter, $csv)); 
    } 
    $arrResults = rsort($arrResults); 
    return (array_keys($arrResults)[0]); 
} 
0

Die kurze Antwort ist, werden Sie wahrscheinlich nicht möglich es sei denn, Sie können eine Heuristik anwenden, um das Dateiformat zu bestimmen. Wenn Sie das Format der zu analysierenden Datei nicht kennen und nicht erkennen können, wird das Parsen schwierig.

Sobald Sie jedoch das Trennzeichenformat bestimmt haben (oder ein bestimmtes benötigt haben). Sie werden wahrscheinlich feststellen, dass die eingebaute fgetcsv von php einfacher und genauer ist als eine manuelle explode basierte Strategie.

0

Nun, es sieht so aus, als ob Sie genau wissen, dass Ihr Trennzeichen "," oder ";" ist. Dies ist ein guter Anfang. Sie können also versuchen, alle Kommata (,) durch Semikolons (;) zu ersetzen und dann nur mit dem Semikolon zu explodieren. Bei diesem Ansatz würden Sie jedoch in einigen Fällen ein Problem haben, da einige Zeilen Ihrer CSV-Dateien wie folgt aussehen könnten:

"Name, Wert", anderer Name, anderer Wert, Nachname; letzter Wert

Auf diese Weise wird das Trennzeichen Ihrer CSV-Datei ein Komma, wenn Ihre CSV-Datei vier Spalten enthält. Wenn Sie jedoch Kommas in Semikola ändern, erhalten Sie fünf Spalten, die falsch sind. Es ist also nicht gut, ein Trennzeichen in ein anderes zu ändern.

Wenn Ihre CSV-Datei jedoch korrekt formatiert ist, können Sie in jeder Zeile das korrekte Trennzeichen finden.Sie können also versuchen, eine Funktion wie find_delimiter ($ csvLine) wie von @johnkork vorgeschlagen zu erstellen, aber das Problem dabei ist, dass die Funktion selbst nicht wissen kann, nach welchem ​​Begrenzer gesucht werden soll. Sie kennen jedoch alle möglichen Trennzeichen genau, also können Sie versuchen, eine andere, ziemlich ähnliche Funktion wie delimiter_exists ($ csvLine, $ delimiter) zu erstellen, die true oder false zurückgibt.

Aber selbst die Funktion delimiter_exists ($ csvLine, $ delimiter) ist nicht genug. Warum? Denn für die oben angegebene Instanz der CSV-Zeile würden Sie sowohl "," als auch ";" sind Begrenzer, die existieren. Für Komma würde es CSV-Datei mit vier Spalten und für Semikolon wäre es zwei Spalten.

So gibt es keinen universellen Weg, der Sie genau bekommen würde, was Sie wollen. Es kann jedoch auch eine andere Möglichkeit geben, nach der Sie suchen können - die erste Zeile der CSV-Datei, bei der es sich um die Kopfzeile handelt, sofern Ihre CSV-Dateien eine Kopfzeile haben. Meistens haben Header in der CSV-Datei (nicht unbedingt) keine anderen Symbole außer den alphanumerischen Namen der Spalten, die durch das spezifische Delimiter getrennt sind. So können Sie versuchen Funktion zu erstellen, wie delimiter_exists ($ csvHeader, $ Trennzeichen), deren Umsetzung so sein könnte:

function delimiter_exists($csvHeader, $delimiter) { 
    return (bool)preg_match("/$delimiter/", $csvHeader); 
} 

Für Sie spezifischen Fall, dass Sie es wie folgt verwenden:

$csvHeader = "abc;def"; 
$delimiter = delimiter_exists($csvHeader, ',') ? ',' : ';'; 

Hoffnung das hilft!

+0

Tatsächlich kann die Funktion find_delimiter nach einer unbegrenzten Anzahl von möglichen Delimitern suchen (siehe das Array $ arrDelimiters). Gehen Sie durch den Header-Abschnitt der CSV-Datei, wie Sie erwähnt haben, ist eine gute Idee, da es die "falsch positive" Zellen wie mit Zahlen mit Dezimalzahlen und Kommas migrieren. :) – johnkork

1

Wenn Sie eine Vorstellung von den erwarteten Daten haben (Anzahl der Spalten), dann könnte dies eine gute Schätzung sein, und könnte eine gute Alternative zum Vergleich sein, die am häufigsten auftritt (je nachdem, welche Art von Daten Sie erwarten). Es würde noch besser funktionieren, wenn Sie einen Header-Datensatz haben, würde ich mir vorstellen. (Sie könnten nach bestimmten Header-Werten suchen)

Entschuldigung dafür, dass ich es nicht in Ihren Code eingefügt habe, aber ich bin nicht wirklich sicher, was diese Anrufe machen, aber Sie sollten in der Lage sein, es anzupassen.

$expected_num_of_columns = 10; 
$delimiter = ""; 

foreach (array(",", ";") as $test_delimiter) { 
    $fid = fopen ($filename, "r"); 
    $csv_row = fgetcsv($fid, 0, $test_delimiter); 
    if (count($csv_row) == $expected_num_of_columns) { 
     $delimiter = $test_delimiter; 
     break; 
    } 
    fclose($fid); 
} 

if (empty($delimiter)) { 
    die ("Input file did not contain the correct number of fields (" . $expected_num_of_columns . ")"); 
} 

nicht das Verwenden, wenn zum Beispiel alle oder die meisten der Felder nicht-Integer-Zahlen (zB einer Liste von Geldbeträgen) enthalten und haben Datensatz keinen Header, weil Dateien von ; getrennt am wahrscheinlichsten Verwenden Sie , als Dezimalpunkt und es könnte die gleiche Anzahl von Kommas und Semikolons geben.