Làm cách nào để đọc dữ liệu từ tệp * .CSV bằng javascript?


192

Dữ liệu csv của tôi trông như thế này:

đề mục 1, đề2, đề 3, đề 4, đề 5, value1_1, value2_1, value3_1, value4_1, value5_1, value1_2, value2_2, value3_2, value4_2, value5_2 ....

Làm thế nào để bạn đọc dữ liệu này và chuyển đổi thành một mảng như thế này bằng Javascript?:

[đề1: value1_1, đề2: value2_1, đề3: value3_1, đề 4: value4_1, đề5: value5_1], [đề1: value1_2, đề2: value2_2, đề3: value3_2, đề4: value4_2, đề5: value5_2

Tôi đã thử mã này nhưng không có may mắn!:

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

Nếu không có ngắt dòng trong tệp CSV của bạn, sẽ không thể có bất kỳ mã JavaScript nào biết nơi một mảng (hoặc đối tượng) dừng lại và mảng kia bắt đầu (trừ khi bạn biết trước rằng luôn có chính xác năm tiêu đề). Đây có phải là một giám sát cắt và dán?
Blazemonger

Vâng, tôi biết trước rằng có chính xác Năm lĩnh vực.
Mahesh Thumar

1
Câu hỏi tiếp theo: jQuery có được phép trong giải pháp không? Bạn đã sử dụng thẻ nhưng mã mẫu của bạn là JavaScript thuần túy.
Blazemonger

vâng, jQuery được cho phép, đó là lý do tại sao tôi đưa nó vào Tag.
Mahesh Thumar

1
Tôi không nghĩ việc sử dụng file://...được cho phép XMLHttpRequest.
Noel Llevares

Câu trả lời:


118

LƯU Ý: Tôi đã tạo ra giải pháp này trước khi tôi được nhắc nhở về tất cả các "trường hợp đặc biệt" có thể xảy ra trong một tệp CSV hợp lệ, như các trích dẫn đã thoát. Tôi đang để lại câu trả lời của mình cho những ai muốn một cái gì đó nhanh chóng và bẩn thỉu, nhưng tôi khuyên bạn nên trả lời chính xác cho Evan .


Mã này sẽ hoạt động khi data.txttệp của bạn là một chuỗi dài các mục được phân tách bằng dấu phẩy, không có dòng mới:

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

Đoạn mã sau sẽ hoạt động trên tệp CSV "thật" với các ngắt dòng giữa mỗi bộ bản ghi:

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/


4
Nhân tiện, điều này giả định rằng tệp CSV trên thực tế có nhiều hàng - đó là những gì allText.split(/\r\n|\n/)phân chia trên. Nếu tất cả dữ liệu của bạn trên thực tế là một chuỗi dài dữ liệu được phân tách bằng dấu phẩy không có dòng mới, thì đó không phải là tệp CSV thực.
Blazemonger

1
Xin chào, tôi đã sử dụng Mã này: Nhưng không có đầu ra. Chỉ cần một cảnh báo trống được hiển thị. tập tin của tôi là nhìn như: 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 Cả csv.html và data.txt là trong cùng một thư mục
Mahesh Thumar

Nếu đây không phải là tệp chính xác (hoặc dữ liệu) thì tệp của tôi sẽ như thế nào ??
Mahesh Thumar

7
Mã này có thể không xử lý tất cả các tệp CSV tiêu chuẩn IETF hợp lệ và có thể không thành công nếu có các chuỗi có dấu phẩy nhúng, ngắt dòng hoặc dấu ngoặc kép. Chẳng hạn, 1, "IETF allows ""quotes"", commas and \nline breaks"được phép vì chuỗi được bao quanh bằng dấu ngoặc kép và dấu ngoặc kép được thoát.
nguyên mẫu

1
Tôi đã cố đọc một tập tin .csv từ máy mac. Tôi chỉ có thể có được kịch bản này để nhận ra các ký tự dòng mới khi tôi thay đổi phân tách đầu tiên thành này var allTextLines = allText.split("\r"); Sau đó nó hoạt động rất tốt! Cảm ơn!
Joe

204

Không cần phải viết ...

Thư viện jQuery-CSV có một chức năng gọi là $.csv.toObjects(csv)ánh xạ tự động.

Lưu ý: Thư viện được thiết kế để xử lý bất kỳ dữ liệu CSV nào tuân thủ RFC 4180 , bao gồm tất cả các trường hợp cạnh khó chịu mà hầu hết các giải pháp 'đơn giản' đều bỏ qua.

Giống như @Blazemonger đã nêu, trước tiên, bạn cần thêm ngắt dòng để làm cho dữ liệu CSV hợp lệ.

Sử dụng bộ dữ liệu sau:

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

Sử dụng mã:

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

Đầu ra được lưu trong 'dữ liệu' sẽ là:

[
  { 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" }
]

Lưu ý: Về mặt kỹ thuật, cách bạn viết ánh xạ khóa-giá trị là JavaScript không hợp lệ. Các đối tượng chứa các cặp khóa-giá trị phải được gói trong ngoặc.

Nếu bạn muốn tự mình dùng thử, tôi khuyên bạn nên xem Trình diễn sử dụng cơ bản trong tab 'toObjects ()'.

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả gốc của jQuery-CSV.

Cập nhật:

Đã chỉnh sửa để sử dụng bộ dữ liệu mà op cung cấp và bao gồm một liên kết đến bản demo nơi dữ liệu có thể được kiểm tra tính hợp lệ.

Cập nhật2:

Do màn trập của Google Code. jquery-csv đã chuyển đến GitHub


3
IOW, "toObject" là hoặc có thể được coi là "toJSON", không? Và, dấu hai chấm sau lệnh gọi toObjects (csv) có phải là lỗi chính tả không? IOW, không nên là một dấu chấm phẩy?
B. Clay Shannon

11
CSV có phải là tên tệp không?
bong bóng

10
Thư viện tuyệt vời. FYI, tham số csvđược truyền là một chuỗi csv - đọc tệp csv dưới dạng văn bản để lấy chuỗi csv.
callmekatootie

3
@Evan Plaice Làm thế nào để sử dụng thư viện này để đọc từ tệp csv?
Richa Sinha

1
@RichaSinha Đọc tệp dưới dạng bộ đệm văn bản thông qua API tệp HTML5 hoặc AJAX. Sau đó chuyển bộ đệm chuỗi vào trình phân tích cú pháp. Kết quả là nó sẽ phun ra một mảng dữ liệu. Xem trang dự án cho ví dụ.
Evan Plaice

75

Không phân chia dấu phẩy - nó sẽ không hoạt động đối với hầu hết các tệp CSV và câu hỏi này có quá nhiều lượt xem cho loại dữ liệu đầu vào của người hỏi để áp dụng cho mọi người. Phân tích cú pháp CSV là loại đáng sợ vì không có tiêu chuẩn thực sự chính thức và rất nhiều nhà văn văn bản được phân tách không xem xét các trường hợp cạnh.

Câu hỏi này đã cũ, nhưng tôi tin rằng có một giải pháp tốt hơn bây giờ là Papa Parse đã có sẵn. Đó là một thư viện tôi đã viết, với sự giúp đỡ từ những người đóng góp, phân tích cú pháp văn bản hoặc tệp CSV. Đây là thư viện JS duy nhất tôi biết có hỗ trợ các tệp có kích thước gigabyte. Nó cũng xử lý đầu vào không đúng định dạng một cách duyên dáng.

Tệp 1 GB được phân tích cú pháp trong 1 phút: Đã phân tích tệp 1 GB trong 1 phút

( Cập nhật: Với Papa Parse 4, cùng một tệp chỉ mất khoảng 30 giây trong Firefox. Papa Parse 4 hiện là trình phân tích cú pháp CSV được biết đến nhanh nhất cho trình duyệt.)

Phân tích văn bản rất dễ dàng:

var data = Papa.parse(csvString);

Phân tích tệp cũng dễ dàng:

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

Truyền tệp tương tự (đây là một ví dụ truyền phát tệp từ xa):

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

Nếu trang web của bạn bị khóa trong quá trình phân tích cú pháp, Papa có thể sử dụng nhân viên web để giữ cho trang web của bạn hoạt động trở lại.

Papa có thể tự động phát hiện các dấu phân cách và khớp giá trị với các cột tiêu đề, nếu có một hàng tiêu đề. Nó cũng có thể biến các giá trị số thành các loại số thực tế. Nó phân tích một cách thích hợp các ngắt dòng và trích dẫn và các tình huống kỳ lạ khác, và thậm chí xử lý đầu vào không đúng định dạng một cách mạnh mẽ nhất có thể. Tôi đã lấy cảm hứng từ các thư viện hiện có để làm Papa, vì vậy đạo cụ cho các triển khai JS khác.


Papa rất dễ sử dụng và nhanh chóng! Cảm ơn!
Technotronic

+1 Công việc tốt trên Papa Parse. Tôi muốn nghiên cứu chi tiết một ngày nào đó để xem cách bạn xử lý các tệp lớn và phát trực tuyến. Tôi rất vui khi thấy các nhà phát triển khác viết các trình phân tích cú pháp đầy đủ tính năng chọn nơi jquery-csv rời đi.
Evan Plaice

3
@EvanPlaice Cảm ơn. Bạn có thể thích bài thuyết trình này tôi đã đưa ra tối qua tại một cuộc họp mặt địa phương: docs.google.com/presentation/d/ Khăn
Matt

1
@ Matt Đó là một bài thuyết trình tuyệt vời mô tả về phân tích papa theo cách hiểu hơn
siva

1
@ Malky.Kid Đó không phải là CSV hợp lệ (nghĩa là khoảng trắng trong giá trị không phân cách là không tốt). Việc triển khai định dạng CSV của MS Excel rất tệ. Nếu bạn vẫn có quyền truy cập vào tệp nguồn, cần có một tùy chọn để bật dấu phân cách trích dẫn. Khi bạn làm điều đó, dữ liệu của bạn sẽ hoạt động với bất kỳ trình phân tích cú pháp csv nào.
Evan Plaice

9

Tôi đang sử dụng d3.js để phân tích tệp csv. Rất dễ sử dụng. Đây là tài liệu .

Các bước:

  • npm cài đặt d3-request

Sử dụng Es6;

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

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

Xin vui lòng xem tài liệu để biết thêm.

Cập nhật - yêu cầu d3 không được chấp nhận. bạn có thể sử dụng d3-fetch



3

Đây là một hàm JavaScript phân tích dữ liệu CSV, chiếm các dấu phẩy được tìm thấy bên trong dấu ngoặc kép.

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

Ví dụ sử dụng hàm để phân tích tệp CSV trông như thế này:

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

thành mảng:

// 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));

Dưới đây là cách bạn có thể chuyển đổi dữ liệu thành các đối tượng, như trình phân tích cú pháp csv của D3 (là giải pháp bên thứ ba vững chắc):

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

Đây là một fiddle làm việc của mã này .

Thưởng thức! - Curran


1

Đây là một cách khác để đọc CSV bên ngoài vào Javascript (sử dụng jQuery).

Hơi dài dòng hơn một chút, nhưng tôi cảm thấy bằng cách đọc dữ liệu thành các mảng, bạn có thể thực hiện chính xác quy trình và xử lý sự cố dễ dàng.

Có thể giúp đỡ người khác.

Ví dụ về tệp dữ liệu:

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

Và đây là mã:

$(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]);
    }
})

Mong rằng điều này sẽ giúp ai đó trong tương lai!


Xin chào từ tương lai, vì vậy tôi đã thử câu trả lời này và nó thiếu một )dấu hiệu ở dòng 45 vì vậy tôi đã thêm nó, nhưng bây giờ trên dòng 9, nó cho tôi một lỗi giao diện điều khiển Uncaught ReferenceError: $ is not defined at index.html:9Bạn có thể hỗ trợ trong việc này không?
Mèo Lasagna

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

Tôi muốn có regex làm càng nhiều càng tốt. Regex này xử lý tất cả các mục như được trích dẫn hoặc không trích dẫn, theo sau là dấu phân cách cột hoặc dấu phân cách hàng. Hoặc kết thúc văn bản.

Đó là lý do tại sao điều kiện cuối cùng - không có nó sẽ là một vòng lặp vô hạn vì mẫu có thể khớp với trường có độ dài bằng không (hoàn toàn hợp lệ trong csv). Nhưng vì $ là một xác nhận có độ dài bằng không, nên nó sẽ không tiến tới một kết quả không khớp và kết thúc vòng lặp.

Và FYI, tôi đã phải đưa ra phương án thứ hai loại trừ các trích dẫn xung quanh giá trị; có vẻ như nó đã được thực thi trước khi thay thế đầu tiên trên công cụ javascript của tôi và coi các trích dẫn là một phần của giá trị không được trích dẫn. Tôi sẽ không hỏi - chỉ cần làm cho nó hoạt động.


Thật không may, tôi đã vào một vòng lặp vô hạn với chức năng này.
Hauke

@Hauke ​​- nếu bạn có thể chia dữ liệu thành một vài cột và dòng vẫn tạo ra vòng lặp vô hạn, tôi sẽ đánh giá cao nó - nó có thể cho tôi hiểu về lý do tại sao tôi thất bại trước đây.
Gerard ONeill

1

Theo câu trả lời được chấp nhận ,

Tôi đã làm việc này bằng cách thay đổi 1 thành 0 tại đây:

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

thay đổi để

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

Nó sẽ tính toán một tệp với một dòng liên tục là có allTextLines.length bằng 1. Vì vậy, nếu vòng lặp bắt đầu ở 1 và chạy miễn là dưới 1, nó sẽ không bao giờ chạy. Do đó hộp cảnh báo trống.


0

Nếu bạn muốn giải quyết vấn đề này mà không cần sử dụng Ajax , hãy sử dụng FileReader()API Web .

Ví dụ thực hiện:

  1. Chọn .csvtập tin
  2. Xem đầu ra

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>


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]);

                        }
                      }
                    }

Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do giải quyết vấn đề này thực sự sẽ giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều lượt bình chọn hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định được áp dụng. Từ đánh giá
tiếng bíp đôi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.