Jak czytać dane z pliku * .CSV przy użyciu javascript?

196

Moje dane csv wyglądają tak:

nagłówek 1, nagłówek 2, nagłówek 3, nagłówek 4, nagłówek 5, wartość1_1, wartość2_1, wartość3_1, wartość4_1, wartość5_1, wartość1_2, wartość2_2, wartość3_2, wartość4_2, wartość5_2 ....

Jak czytasz te dane i konwertujesz na taką tablicę za pomocą Javascript ?:

[nagłówek1: wartość1_1, nagłówek2: wartość2_1, nagłówek3: wartość3_1, nagłówek4: wartość4_1, nagłówek5: wartość5_1], [nagłówek1: wartość1_2, nagłówek2: wartość2_2, nagłówek3: wartość3_2, nagłówek4: wartość4_2, nagłówek5: wartość5_2] ....

Próbowałem tego kodu, ale bez powodzenia !:

<script type="text/javascript">
    var allText =[];
    var allTextLines = [];
    var Lines = [];

    var txtFile = new XMLHttpRequest();
    txtFile.open("GET", "file://d:/data.txt", true);
    txtFile.onreadystatechange = function()
    {
        allText = txtFile.responseText;
        allTextLines = allText.split(/\r\n|\n/);
    };

    document.write(allTextLines);<br>
    document.write(allText);<br>
    document.write(txtFile);<br>
</script>
Mahesh Thumar
źródło
Bez podziałów wierszy w pliku CSV żaden kod JavaScript nie będzie wiedział, gdzie kończy się jedna tablica (lub obiekt), a zaczyna druga (chyba że wiesz wcześniej, że zawsze jest dokładnie pięć nagłówków). Czy był to nadzór „wklej i wklej”?
Blazemonger,
Tak, wiem z góry, że istnieje dokładnie pięć pól.
Mahesh Thumar,
1
Następne pytanie: czy jQuery jest dozwolone w rozwiązaniu? Użyłeś tagu, ale przykładowy kod to czysty JavaScript.
Blazemonger,
tak, jQuery jest dozwolone, dlatego umieszczam go w tagu.
Mahesh Thumar,
1
Nie sądzę, żeby użycie file://...było dozwolone XMLHttpRequest.
Noel Llevares

Odpowiedzi:

118

UWAGA: Wymyśliłem to rozwiązanie, zanim przypomniano mi o „specjalnych przypadkach”, które mogą wystąpić w prawidłowym pliku CSV, takich jak cytaty. Pozostawiam moją odpowiedź tym, którzy chcą czegoś szybkiego i brudnego, ale polecam odpowiedź Evana ze względu na dokładność.


Ten kod będzie działał, gdy data.txtplik zawiera jeden długi ciąg znaków oddzielonych przecinkami, bez znaków nowej linii:

data.txt:

 heading1,heading2,heading3,heading4,heading5,value1_1,...,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var record_num = 5;  // or however many elements there are in each row
    var allTextLines = allText.split(/\r\n|\n/);
    var entries = allTextLines[0].split(',');
    var lines = [];

    var headings = entries.splice(0,record_num);
    while (entries.length>0) {
        var tarr = [];
        for (var j=0; j<record_num; j++) {
            tarr.push(headings[j]+":"+entries.shift());
        }
        lines.push(tarr);
    }
    // alert(lines);
}

Poniższy kod będzie działał na „prawdziwym” pliku CSV z podziałem wierszy między każdym zestawem rekordów:

data.txt:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

javascript:

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

function processData(allText) {
    var allTextLines = allText.split(/\r\n|\n/);
    var headers = allTextLines[0].split(',');
    var lines = [];

    for (var i=1; i<allTextLines.length; i++) {
        var data = allTextLines[i].split(',');
        if (data.length == headers.length) {

            var tarr = [];
            for (var j=0; j<headers.length; j++) {
                tarr.push(headers[j]+":"+data[j]);
            }
            lines.push(tarr);
        }
    }
    // alert(lines);
}

http://jsfiddle.net/mblase75/dcqxr/

Blazemonger
źródło
4
Nawiasem mówiąc, zakłada się, że plik CSV faktycznie ma wiele wierszy - na tym właśnie polega allText.split(/\r\n|\n/)podział. Jeśli wszystkie dane są w rzeczywistości jednym długim ciągiem danych oddzielonych przecinkami bez znaków nowej linii, nie jest to prawdziwy plik CSV.
Blazemonger,
1
Cześć. Korzystam z tego kodu: Ale nie ma danych wyjściowych. Wyświetlany jest tylko pusty alert. mój plik wygląda następująco: nagłówek 1, nagłówek 2, nagłówek 3, nagłówek 4, nagłówek 5, wartość1_1, wartość2_1, wartość3_1, wartość4_1, wartość5_1, wartość1_2, wartość2_2, wartość3_2, wartość4_2, wartość5_2 Zarówno csv.html, jak i data.txt znajdują się w tym samym folderze
Mahesh Thumar
Jeśli to nie jest poprawny plik (lub dane), to jak powinien wyglądać mój plik?
Mahesh Thumar,
7
Kod może nie obsługiwać wszystkich prawidłowych plików CSV w standardzie IETF i może zawieść, jeśli istnieją ciągi znaków z osadzonymi przecinkami, podziałami wierszy lub podwójnymi cudzysłowami. Na przykład, 1, "IETF allows ""quotes"", commas and \nline breaks"co jest dozwolone, ponieważ ciąg znaków jest otoczony podwójnymi cudzysłowami, a podwójne cudzysłowy są poprzedzane znakami ucieczki.
prototyp
1
Próbowałem odczytać plik .csv z komputera Mac. Byłem w stanie sprawić, by ten skrypt rozpoznał znaki nowego wiersza, kiedy zmieniłem pierwszy podział na ten. var allTextLines = allText.split("\r"); Potem zadziałało świetnie! Dzięki!
Joe
207

Nie musisz pisać własnego ...

The jQuery-CSV ma wywoływaną funkcję, $.csv.toObjects(csv)która wykonuje mapowanie automatycznie.

Uwaga: Biblioteka została zaprojektowana do obsługi danych CSV zgodnych z RFC 4180 , w tym wszystkich nieprzyjemnych przypadków brzegowych, które przeoczają większość „prostych” rozwiązań.

Jak już wspomniano w @Blazemonger, najpierw musisz dodać podział wiersza, aby dane były prawidłowe CSV.

Za pomocą następującego zestawu danych:

heading1,heading2,heading3,heading4,heading5
value1_1,value2_1,value3_1,value4_1,value5_1
value1_2,value2_2,value3_2,value4_2,value5_2

Użyj kodu:

var data = $.csv.toObjects(csv):

Dane wyjściowe zapisane w „danych” będą:

[
  { heading1:"value1_1",heading2:"value2_1",heading3:"value3_1",heading4:"value4_1",heading5:"value5_1" } 
  { heading1:"value1_2",heading2:"value2_2",heading3:"value3_2",heading4:"value4_2",heading5:"value5_2" }
]

Uwaga: Technicznie sposób, w jaki napisałeś mapowanie klucz-wartość, jest nieprawidłowy JavaScript. Obiekty zawierające pary klucz-wartość powinny być owinięte w nawiasy.

Jeśli chcesz to wypróbować sam, sugeruję, abyś zapoznał się z Podstawową demonstracją użycia w zakładce „toObjects ()”.

Oświadczenie: Jestem oryginalnym autorem jQuery-CSV.

Aktualizacja:

Edytowano, aby użyć zestawu danych dostarczonego przez operację i zawierał link do wersji demonstracyjnej, w której dane można przetestować pod kątem ważności.

Aktualizacja 2:

Z powodu wyłączenia kodu Google. jquery-csv został przeniesiony do GitHub

Evan Plaice
źródło
3
IOW, „toObject” jest lub może być uważane za „toJSON”, nie? I czy dwukropek po wywołaniu funkcji toObjects (csv) jest literówką? IOW, czy to nie powinien być średnik?
B. Clay Shannon
11
Czy CSV to nazwa pliku?
bubble
10
Fantastyczna biblioteka. FYI, csvprzekazany parametr to ciąg csv - przeczytaj plik csv jako tekst, aby uzyskać ciąg csv.
callmekatootie
3
@Evan Plaice Jak korzystać z tej biblioteki do czytania z pliku csv?
Richa Sinha
1
@RichaSinha Wczytaj plik jako bufor tekstowy za pośrednictwem interfejsu API plików HTML5 lub AJAX. Następnie przekaż bufor ciągów do analizatora składni. W rezultacie wypluje tablicę danych. Przykłady znajdują się na stronie projektu.
Evan Plaice,
75

Nie dziel przecinków - nie będzie działać dla większości plików CSV, a to pytanie ma zdecydowanie zbyt wiele widoków, aby dane wejściowe pytającego mogły zostać zastosowane do wszystkich. Analiza CSV jest trochę przerażająca, ponieważ nie ma naprawdę oficjalnego standardu, a wielu pisarzy z ogranicznikami nie bierze pod uwagę przypadków skrajnych.

To pytanie jest stare, ale uważam, że istnieje lepsze rozwiązanie niż Papa Parse jest dostępny. To biblioteka, którą napisałem, z pomocą autorów, analizuje tekst lub pliki CSV. To jedyna znana mi biblioteka JS, która obsługuje pliki o wielkości gigabajtów. Z wdziękiem obsługuje również zniekształcone dane wejściowe.

Plik 1 GB parsowany w ciągu 1 minuty: Przetwarzano 1 GB pliku w ciągu 1 minuty

( Aktualizacja: W przypadku Papa Parse 4 ten sam plik zajął tylko 30 sekund w Firefoksie. Papa Parse 4 jest teraz najszybciej znanym parserem CSV dla przeglądarki).

Analiza tekstu jest bardzo łatwa:

var data = Papa.parse(csvString);

Parsowanie plików jest również łatwe:

Papa.parse(file, {
    complete: function(results) {
        console.log(results);
    }
});

Przesyłanie strumieniowe plików jest podobne (oto przykład przesyłania strumieniowego pliku zdalnego):

Papa.parse("http://example.com/bigfoo.csv", {
    download: true,
    step: function(row) {
        console.log("Row:", row.data);
    },
    complete: function() {
        console.log("All done!");
    }
});

Jeśli twoja strona blokuje się podczas analizy, Papa może korzystać z robotów WWW, aby utrzymać twoją stronę.

Tata może automatycznie wykrywać ograniczniki i dopasowywać wartości do kolumn nagłówka, jeśli obecny jest wiersz nagłówka. Może także przekształcać wartości liczbowe w rzeczywiste typy liczb. Odpowiednio analizuje podziały wierszy, cytaty i inne dziwne sytuacje, a nawet obsługuje zniekształcone dane wejściowe tak solidnie, jak to możliwe. Czerpałem inspirację z istniejących bibliotek, aby stworzyć Papa, więc podpieram się innymi implementacjami JS.

Matt
źródło
Papa jest łatwy w użyciu i szybki! Dzięki!
Technotronic,
+1 Dobra robota na Papa Parse. Chciałbym kiedyś to szczegółowo przestudiować, aby zobaczyć, jak radzisz sobie z dużymi plikami i przesyłaniem strumieniowym. Bardzo się cieszę, że inni programiści piszą w pełni funkcjonalne parsery, które zbierają informacje o tym, gdzie zakończyło się jquery-csv.
Evan Plaice,
3
@EvanPlaice Dzięki. Może ci się spodobać ta prezentacja, którą wygłosiłem wczoraj na lokalnym spotkaniu: docs.google.com/presentation/d/…
Matt
1
@ Matt To była niesamowita prezentacja, która w bardziej zrozumiały sposób opisuje parsę papy
siva
1
@ Malky.Kid To nie jest poprawny CSV (tzn. Spacje w wartościach bez wartości rozdzielających nie są dobre). Implementacja formatu CSV MS Excel jest do kitu. Jeśli nadal masz dostęp do pliku źródłowego, powinna istnieć opcja włączenia ograniczników cytatów. Po wykonaniu tej czynności dane powinny działać z dowolnym analizatorem składni csv.
Evan Plaice,
10

Używam d3.js do parsowania pliku csv. Bardzo łatwy w użyciu. Oto dokumenty .

Kroki:

  • npm zainstaluj żądanie d3

Korzystanie z Es6;

import { csv } from 'd3-request';
import url from 'path/to/data.csv';

csv(url, function(err, data) {
 console.log(data);
})

Więcej informacji można znaleźć w dokumentacji .

Aktualizacja - żądanie d3 jest nieaktualne. możesz użyć d3-fetch

Bimal Grg
źródło
3

Oto funkcja JavaScript, która analizuje dane CSV, uwzględniając przecinki znalezione w cudzysłowach.

// Parse a CSV row, accounting for commas inside quotes                   
function parse(row){
  var insideQuote = false,                                             
      entries = [],                                                    
      entry = [];
  row.split('').forEach(function (character) {                         
    if(character === '"') {
      insideQuote = !insideQuote;                                      
    } else {
      if(character == "," && !insideQuote) {                           
        entries.push(entry.join(''));                                  
        entry = [];                                                    
      } else {
        entry.push(character);                                         
      }                                                                
    }                                                                  
  });
  entries.push(entry.join(''));                                        
  return entries;                                                      
}

Przykład użycia funkcji do analizy pliku CSV, który wygląda następująco:

"foo, the column",bar
2,3
"4, the value",5

w tablice:

// csv could contain the content read from a csv file
var csv = '"foo, the column",bar\n2,3\n"4, the value",5',

    // Split the input into lines
    lines = csv.split('\n'),

    // Extract column names from the first line
    columnNamesLine = lines[0],
    columnNames = parse(columnNamesLine),

    // Extract data from subsequent lines
    dataLines = lines.slice(1),
    data = dataLines.map(parse);

// Prints ["foo, the column","bar"]
console.log(JSON.stringify(columnNames));

// Prints [["2","3"],["4, the value","5"]]
console.log(JSON.stringify(data));

Oto jak możesz przekształcić dane w obiekty, takie jak parser csv D3 (który jest solidnym rozwiązaniem strony trzeciej):

var dataObjects = data.map(function (arr) {
  var dataObject = {};
  columnNames.forEach(function(columnName, i){
    dataObject[columnName] = arr[i];
  });
  return dataObject;
});

// Prints [{"foo":"2","bar":"3"},{"foo":"4","bar":"5"}]
console.log(JSON.stringify(dataObjects));

Oto działające skrzypce tego kodu .

Cieszyć się! - Curran

curran
źródło
1

Oto inny sposób na odczyt zewnętrznego CSV do Javascript (przy użyciu jQuery).

Jest trochę bardziej skomplikowany, ale czuję, że wczytując dane do tablic, możesz dokładnie śledzić proces i ułatwia rozwiązywanie problemów.

Może pomóc komuś innemu.

Przykład pliku danych:

Time,data1,data2,data2
08/11/2015 07:30:16,602,0.009,321

A oto kod:

$(document).ready(function() {
 // AJAX in the data file
    $.ajax({
        type: "GET",
        url: "data.csv",
        dataType: "text",
        success: function(data) {processData(data);}
        });

    // Let's process the data from the data file
    function processData(data) {
        var lines = data.split(/\r\n|\n/);

        //Set up the data arrays
        var time = [];
        var data1 = [];
        var data2 = [];
        var data3 = [];

        var headings = lines[0].split(','); // Splice up the first row to get the headings

        for (var j=1; j<lines.length; j++) {
        var values = lines[j].split(','); // Split up the comma seperated values
           // We read the key,1st, 2nd and 3rd rows 
           time.push(values[0]); // Read in as string
           // Recommended to read in as float, since we'll be doing some operations on this later.
           data1.push(parseFloat(values[1])); 
           data2.push(parseFloat(values[2]));
           data3.push(parseFloat(values[3]));

        }

    // For display
    var x= 0;
    console.log(headings[0]+" : "+time[x]+headings[1]+" : "+data1[x]+headings[2]+" : "+data2[x]+headings[4]+" : "+data2[x]);
    }
})

Mam nadzieję, że to pomoże komuś w przyszłości!

FredFury
źródło
Witam z przyszłości, więc wypróbowałem tę odpowiedź i brakowało )znaku w linii 45, więc dodałem ją, ale teraz w linii 9 daje mi błąd konsoli. Uncaught ReferenceError: $ is not defined at index.html:9Czy mógłbyś w tym pomóc?
Lasagna Cat,
1
function CSVParse(csvFile)
{
    this.rows = [];

    var fieldRegEx = new RegExp('(?:\s*"((?:""|[^"])*)"\s*|\s*((?:""|[^",\r\n])*(?:""|[^"\s,\r\n]))?\s*)(,|[\r\n]+|$)', "g");   
    var row = [];
    var currMatch = null;

    while (currMatch = fieldRegEx.exec(this.csvFile))
    {
        row.push([currMatch[1], currMatch[2]].join('')); // concatenate with potential nulls

        if (currMatch[3] != ',')
        {
            this.rows.push(row);
            row = [];
        }

        if (currMatch[3].length == 0)
            break;
    }
}

Lubię mieć regex zrobić jak najwięcej. Wyrażenie regularne traktuje wszystkie elementy jako cudzysłowy lub cudzysłowy, po których następuje separator kolumny lub separator wiersza. Lub koniec tekstu.

Dlatego właśnie ten ostatni warunek - bez niego byłby nieskończoną pętlą, ponieważ wzorzec może pasować do pola o zerowej długości (całkowicie poprawne w csv). Ale ponieważ $ jest twierdzeniem o zerowej długości, nie przejdzie do niezgodności i nie zakończy pętli.

I do twojej wiadomości, musiałem zrobić drugą alternatywę, aby wykluczyć cytaty otaczające wartość; wygląda na to, że działał on przed pierwszą alternatywą w moim silniku JavaScript i biorąc pod uwagę cytaty jako część niecytowanej wartości. Nie zapytam - po prostu mam to do pracy.

Gerard ONeill
źródło
Niestety dostałem się w nieskończoną pętlę z tą funkcją.
Hauke
@ Hauke ​​- jeśli możesz podzielić dane na kilka kolumn i linii, które nadal tworzą nieskończoną pętlę, doceniłbym to - może dać mi wgląd w to, dlaczego wcześniej zawiodłem.
Gerard ONeill,
1

Na tej akceptowanej odpowiedzi ,

Mam to do pracy, zmieniając tutaj 1 na 0:

for (var i=1; i<allTextLines.length; i++) {

zmienić na

for (var i=0; i<allTextLines.length; i++) {

Obliczy plik z jedną linią ciągłą jako mający allTextLines.length 1. Więc jeśli pętla zaczyna się od 1 i działa tak długo, jak jest mniejsza niż 1, nigdy nie działa. Stąd puste pole ostrzeżenia.

Adam Grant
źródło
0

Jeśli chcesz rozwiązać ten problem bez użycia Ajax , użyj FileReader()interfejsu API sieci Web .

Przykładowa implementacja:

  1. Wybierz .csvplik
  2. Zobacz dane wyjściowe

function readSingleFile(e) {
  var file = e.target.files[0];
  if (!file) {
    return;
  }

  var reader = new FileReader();
  reader.onload = function(e) {
    var contents = e.target.result;
    displayContents(contents);
    displayParsed(contents);
  };
  reader.readAsText(file);
}

function displayContents(contents) {
  var element = document.getElementById('file-content');
  element.textContent = contents;
}

function displayParsed(contents) {
  const element = document.getElementById('file-parsed');
  const json = contents.split(',');
  element.textContent = JSON.stringify(json);
}

document.getElementById('file-input').addEventListener('change', readSingleFile, false);
<input type="file" id="file-input" />

<h3>Raw contents of the file:</h3>
<pre id="file-content">No data yet.</pre>

<h3>Parsed file contents:</h3>
<pre id="file-parsed">No data yet.</pre>

Robin Rpr.
źródło
0
$(function() {

      $("#upload").bind("click", function() {
            var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.xlsx)$/;
            if (regex.test($("#fileUpload").val().toLowerCase())) {
              if (typeof(FileReader) != "undefined") {
                var reader = new FileReader();
                reader.onload = function(e) {
                    var customers = new Array();
                    var rows = e.target.result.split("\r\n");
                    for (var i = 0; i < rows.length - 1; i++) {
                      var cells = rows[i].split(",");
                      if (cells[0] == "" || cells[0] == undefined) {
                        var s = customers[customers.length - 1];
                        s.Ord.push(cells[2]);
                      } else {
                        var dt = customers.find(x => x.Number === cells[0]);
                        if (dt == undefined) {
                          if (cells.length > 1) {
                            var customer = {};
                            customer.Number = cells[0];
                            customer.Name = cells[1];
                            customer.Ord = new Array();

                            customer.Ord.push(cells[2]);
                            customer.Point_ID = cells[3];
                            customer.Point_Name = cells[4];
                            customer.Point_Type = cells[5];
                            customer.Set_ORD = cells[6];
                            customers.push(customer);
                          }
                        } else {
                          var dtt = dt;
                          dtt.Ord.push(cells[2]);

                        }
                      }
                    }
rahul kulkarni
źródło
Chociaż ten kod może rozwiązać pytanie, w tym wyjaśnienie, w jaki sposób i dlaczego to rozwiązuje problem, naprawdę pomógłby poprawić jakość twojego postu i prawdopodobnie doprowadziłby do większej liczby głosów. Pamiętaj, że odpowiadasz na pytanie dla czytelników w przyszłości, nie tylko dla osoby zadającej teraz pytanie. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia. Z recenzji
podwójny sygnał dźwiękowy
0

W rzeczywistości możesz użyć lekkiej biblioteki o nazwie dowolny tekst .

  • zainstalować zależności
npm i -D any-text
  • użyj polecenia niestandardowego, aby odczytać pliki
var reader = require('any-text');
 
reader.getText(`path-to-file`).then(function (data) {
  console.log(data);
});

lub użyj asynchronicznego oczekiwania:

var reader = require('any-text');
 
const chai = require('chai');
const expect = chai.expect;
 
describe('file reader checks', () => {
  it('check csv file content', async () => {
    expect(
      await reader.getText(`${process.cwd()}/test/files/dummy.csv`)
    ).to.contains('Lorem ipsum');
  });
});
Abhinaba
źródło