2015-05-27 13 views
6

kiedy wybuchnie csv plik na separator (;) Pomyślnie eksplodować w niektórych excel program i nie powiodło się w innychrozbić plik csv na ogranicznik (;) i ogranicznik (,)?

także kiedy wybuchnie pliku csv na ogranicznik (,) Pomyślnie eksplodować w niektórych excel program i nie powiodło się inne

Jak mogę dokonać eksplozji we wszystkich wersjach programu Excel? Skąd mogę wiedzieć, że idealny ogranicznik może eksplodować?

tak jest kod ..

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; 
    } 
} 

czasami kładę $ separator = ""; i sometims $ delimiter = ",";

Dzięki ..

+2

nie można. Separator, którego używa każda instancja MS Excel, jest zależny od ustawień narodowych, zazwyczaj w zależności od tego, czy kraj, w którym jest skonfigurowany, używa separatora dziesiętnego jako ',' lub '.' ... częściej występuje'; ', ale nie ma uniwersalnej odpowiedzi ... gdyby tak było, nie musiałbyś nawet pytać –

+0

Jest to jeden z powodów, dla których CSV nie jest dobrym formatem do użycia jako alternatywa dla rodzimych formatów Excela –

+0

Czy masz jakiś kod do wyświetlenia nas? Czy próbujesz odczytać plik, a następnie rozbić linie lub używasz fgetcsv? – foxbeefly

Odpowiedz

1

Można używać funkcji pomocnika wykryć najlepszą separator jak:

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

Nie ma sposobu, aby być w 100% pewien, że są kierowane prawdziwą ogranicznik. Wszystko, co możesz zrobić, to zgadywanie.

Powinieneś zacząć od znalezienia odpowiedniego ogranicznika, a następnie rozbić plik CSV na tym ograniczniku.

Aby znaleźć separator, w zasadzie potrzebujesz funkcji, która zlicza numer , i liczby ; i zwraca większy.

Coś jak:

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

Nadzieja pomaga;)

Edit: Twoja funkcja find_delimiter może być coś takiego:

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

Odpowiedź jest krótka, to prawdopodobnie nie może chyba że możesz zastosować heurystykę, aby określić format pliku. Jeśli nie wiesz i nie możesz wykryć formatu pliku, który analizujesz, parsowanie go będzie trudne.

Jednak po ustaleniu (lub, w danym przypadku, określonego) formatu separatora. Najprawdopodobniej okaże się, że wbudowany w php wbudowany sterownik jest łatwiejszy i dokładniejszy niż strategia oparta na instrukcji ręcznej.

0

Wygląda na to, że dokładnie wiesz, że separator będzie "," lub ";". To dobre miejsce na rozpoczęcie. W ten sposób możesz spróbować zastąpić przecinki (,) średnikami (;), a następnie eksplodować tylko średnikiem. Jednak w tym podejściu z pewnością wystąpiłby problem w niektórych przypadkach, ponieważ niektóre wiersze plików CSV mogą wyglądać następująco:

"nazwa, wartość", inna nazwa, inna wartość, nazwisko, ostatnia wartość

W ten sposób ogranicznik pliku CSV będzie przecinkiem, jeśli w pliku CSV będą znajdować się cztery kolumny. Jednak, zmieniając przecinki na średniki, otrzymasz pięć kolumn, które będą niepoprawne. Zatem zmiana ogranicznika na inną nie jest dobrym wyjściem.

Ale nadal, jeśli twój plik CSV jest poprawnie sformatowany, możesz znaleźć właściwy ogranicznik w dowolnej z linii.Tak więc, możesz spróbować utworzyć jakąś funkcję, taką jak find_delimiter ($ csvLine), jak zaproponował @johnkork, ale problem polega na tym, że sama funkcja nie może wiedzieć, który separator szukać. Jednak dokładnie znasz wszystkie możliwe separatory, więc możesz spróbować stworzyć inną, całkiem podobną funkcję, jak delimiter_exists ($ csvLine, $ delimiter), która zwraca true lub false.

Ale nawet funkcja delimiter_exists ($ csvLine, $ delimiter) nie wystarcza. Czemu? Ponieważ dla przykładu powyższej linii CSV otrzymasz zarówno ",", jak i ";" są ograniczniki, które istnieją. Dla przecinka będzie to plik CSV z czterema kolumnami, a dla średnika będzie to dwie kolumny.

W ten sposób nie ma uniwersalnej drogi, która dostarczyłaby ci dokładnie tego, czego chcesz. Może być jednak inny sposób sprawdzenia - pierwszy wiersz pliku CSV, który jest nagłówkiem zakładającym, że twoje pliki CSV mają nagłówek. Przeważnie nagłówki w pliku CSV nie mają (niekoniecznie) żadnych innych symboli, z wyjątkiem alfanumerycznych nazw kolumn, które są ograniczone ograniczeniem. Tak więc, można spróbować stworzyć funkcję jak delimiter_exists ($ csvHeader, $ separator), którego realizacja może być tak:

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

Dla ciebie szczególny przypadek można go używać tak:

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

Nadzieja to pomaga!

+0

W rzeczywistości funkcja find_delimiter jest w stanie wyszukać nieograniczoną podaną listę potencjalnych separatorów (zobacz tablicę $ arrDelimiters). Przechodzenie przez sekcję nagłówka pliku CSV, o którym wspomniałeś, jest dobrym pomysłem, ponieważ migruje on komórki "fałszywie dodatnie", takie jak liczby z cyframi dziesiętnymi i śpiączką. :) – johnkork

1

Jeśli masz pojęcie o oczekiwanych danych (liczba kolumn), to może to być dobre przypuszczenie i może być dobrą alternatywą dla porównywania, które występuje najczęściej (w zależności od rodzaju oczekiwanych danych). Byłoby jeszcze lepiej, gdybyś miał rekord nagłówka, tak sobie wyobrażam. (Możesz wprowadzić sprawdzanie konkretnych wartości nagłówków)

Przepraszamy za niepasowanie go do kodu, ale nie jestem do końca pewien, co robisz, ale powinieneś być w stanie go dopasować.

$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 . ")"); 
} 

Nie używaj tego jeśli, na przykład, wszystkie lub większość pól zawierają numery non-Integer (np wykaz kwot pieniężnych) i nie ma rekordu nagłówka, ponieważ pliki oddzielone ; najprawdopodobniej używać , jako kropki dziesiętnej i może być taka sama liczba przecinków i średników.

Powiązane problemy