博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
csv表格处理(下)--纯JS解析导入csv
阅读量:6907 次
发布时间:2019-06-27

本文共 4922 字,大约阅读时间需要 16 分钟。

介绍了csv表格,以及JS结合后端PHP解析表格填充表单的方法。其中csv转换成二维数组的时候逻辑比较复杂多坑,幸好PHP有丰富的库函数来处理,而现在用JS解析的话就没有那么幸运了,一切都要自己撸一个出来 或者 →_→ 引入一个库。

JS导入CSV--读取文本

JS能前端读取文件吗?以前只有通过 IE的ActiveXObject或者Flash才能本地读取文件。随着H5的出现,这个问题有普遍解了。Talk is cheap,show you the code

$.fn.csv2arr = function( ){    var files = $(this)[0].files;    if( typeof(FileReader) !== 'undefined' ){    //H5        var reader = new FileReader();        reader.readAsText( files[0] );            //以文本格式读取        reader.onload = function(evt){            var data = evt.target.result;        //读到的数据            console.log(data);        }    }else{        alert("IE9及以下浏览器不支持,请使用Chrome或Firefox浏览器");    }}//调用方法$("#startBtn").click(function(){    $("#csvInput").csv2arr();});

这里的关键就是 FileReader,是H5标准里的读取文件的一个标准实现方式,IE10及以上版本以及chrome/firefox/safari等支持。调用方式方法也比较简单,只需要传入文件输入框的DOM,设定读取方式然后绑定回调函数就行了。这里使用的是 readAsText() 的方式,读取为文本格式。参考,还有以base64,二进制等方式,可自行参考尝试。UTF8文本文件读取如下:

注意:readAsText()会自动把utf8文件的BOM头(如果有的话)去除,其它读取方式要注意手动去除。

 

题外话:为什么H5会出现这种直接读取本地文件的API,对安全的威胁大吗?其实这对浏览器用户的安全威胁是基本上没有扩大的,试想一下,原来没有这种读本地文件的API的时候,网站有没有获取本地文件的权限?当然是有的,还是通过这个input type="file",绑定一个onchange事件到 Ajax提交,用户的文件就悄悄地传到网站后端去了。这问题还是得靠提高网民的安全意识,像以前的钓鱼盗号网站,伪造个QQ登录界面就能坐收渔利。这种也能伪造一个下载按钮和对话框,诱导用户把重要机密文件上传上去。

JS导入CSV--文本解析插件

因为JS没有像PHP那样的CSV处理函数,上一篇文章说到里面有不少复杂情况要处理,那么最机(鸡)智(贼)的方法当然是:找插件。其中用的人最多的csv插件是。经典的使用方法如下

// Parse local CSV file$("#csvBtn").click(function(){    var file = $("input[name=csv]").[0].files[0];    Papa.parse(file, {        complete: function(results) {            console.log("Finished:", results.data);        }    });});

这个插件比较强大,解析上基本没有什么大问题,但仍然不是十分完善。问题如下:

  1. 文件最末尾的空行没有自动去除,可能会导致表单填多一点空数据;
  2. 不能自动识别UTF8与GBK,中文解析可能乱码;
  3. UTF8编码下, \r\n与\n混用时有可能会解析出问题,这个是PapaParse解析的算法问题,还请高手去提供修复。

JS导入CSV--编码自动识别

刚说到的第三点,如果表格内容有中文的话,就是个大问题了。因为一般网页的编码是UTF8,导出的表格也会是UTF8编码格式,如果不修改直接上传则为UTF8。但是如果修改,Windows平台下的常用表格软件包括Office和WPS全都将其转换成GBK编码。如果程序没有自动识别编码处理,将有很大概率导致乱码。

另一方面,如果网页使用GBK编码格式下载,也不能确保用户上传的文件就一定是GBK,因为MAC系统用的是UTF8,可能本来GBK的在修改后就成了UTF8了。

或者可以给个下拉栏让用户手动选择编码格式,但是你要指导用户知道编码格式是什么东西,怎么查看,这可不是什么容易让人接受的事。那怎么做编码自动识别呢?UTF8与GBK是不是有明显的编码特征用以区分,报歉的是还真没有。那怎么办?找轮子。在哪找?对于JS的轮子,国内有个,虽然介绍是全英的但还是很好找。我们要找的是编码解码,那就Ctrl+F搜 encod (encode和encoding的前面几个单词),一个个看看介绍,还真能找到一个,名为jschardet。

点进去,没有详细说明,那就再去其github页。看看示例代码

// "àíàçã" in UTF-8jschardet.detect("\xc3\xa0\xc3\xad\xc3\xa0\xc3\xa7\xc3\xa3")// { encoding: "UTF-8", confidence: 0.9690625 }// "次常用國字標準字體表" in Big5jschardet.detect("\xa6\xb8\xb1\x60\xa5\xce\xb0\xea\xa6\x72\xbc\xd0\xb7\xc7\xa6\x72\xc5\xe9\xaa\xed")// { encoding: "Big5", confidence: 0.99 }

什么鬼?看起来用的好像不是普通字符串啊,看起来像是十六进制码的样子。实践了发现,传普通字符串进去全部都是识别为ASCII编码,确实有点难搞啊。怎么办呢?

莫慌莫慌,我们不是要读取本地文件拿来解析吗?再看看除了readAsText()读取为字符串以外还有什么方法可以用。有个readAsBinaryString(),但是并不是标准的H5读取方法,有些浏览器可能不支持。再看有一个readAsDataURL(),这什么东西呢,试试便知道。结果得到一串这样的东西

data:text/csv;base64,NiywzczYwPvM2KGksLIKMyzN0LDdtvLLuaGkx+0KOCy2xc3+oaS3xrDCxMkK

改文件再试多几次,原来是这样子的:前面的 data:text/csv;base64, 是固定字符串,仅对火狐,chrome和IE前面的是 data:;base64, ,后面的那一串是文件内容经过base64编码而成。那么把后面这个一串解码出来看看,IE>=10、火狐、chrome有原生的base64解码函数 atob()。然后就得到了一个英文正常,中文全是乱码的字符串了,而且这个字符串的乱码看起来不像UTF8也不像GBK。那么很可能这就是十六进制码了吧,用jschardet检测一下,成功了!

总结整理

到这里,我们已经用第三方的JS解决了最大的两个难题,编码识别和CSV解析。那么就把这些整合一下,封装成一个更方便调用的方法吧

/** * csv file to 2D arr * */$.fn.csv2arr = function( callback ){    if( typeof(FileReader) == 'undefined' ){    //if not H5        alert("IE9及以下浏览器不支持,请使用Chrome或Firefox浏览器\nYour browser is too old,please use Chrome or Firefox");        return false;    }    if( ! $(this)[0].files[0]){        alert("请选择文件\nPlease select a file");        return false;    }    var fReader = new FileReader();    fReader.readAsDataURL( $(this)[0].files[0] );    $fileDOM = $(this);    fReader.onload = function(evt){        var data = evt.target.result;//        console.log( data );        var encoding = checkEncoding( data );//        console.log(encoding);        //转换成二维数组,需要引入Papaparse.js        Papa.parse( $($fileDOM)[0].files[0], {            encoding: encoding,            complete: function(results) {        // UTF8 \r\n与\n混用时有可能会出问题//                console.log(results);                var res = results.data;                if( res[ res.length-1 ] == ""){    //去除最后的空行                    res.pop();                }                callback && callback( res );            }        });    }    fReader.onerror = function(evt){//        console.log(evt);        alert("文件已修改,请重新选择(Firefox)\nThe file has changed,please select again.(Firefox)");    }        //检查编码,引用了 jschardet    function checkEncoding( base64Str ){        //这种方式得到的是一种二进制串        var str = atob( base64Str.split(";base64,")[1] );//        console.log(str);        //要用二进制格式        var encoding = jschardet.detect( str );        encoding = encoding.encoding;//        console.log( encoding );        if( encoding == "windows-1252"){    //有时会识别错误(如UTF8的中文二字)            encoding = "ANSI";        }        return encoding;    }}

 

使用例子

下载与更新

演示地址

下载

DRY--Don't Repeat Yourself. 别乱造些满是bug的轮子?

转载于:https://www.cnblogs.com/batsing/p/csv2.html

你可能感兴趣的文章
delegation
查看>>
mui 事件绑定(on)
查看>>
ListView 九宫格布局实现
查看>>
spring aop 声明式事务管理
查看>>
List源码学习之LinkedList
查看>>
Kotlin入门(11)江湖绝技之特殊函数
查看>>
Java生日计算年龄工具
查看>>
设计模式学习笔记(4)——单例模式
查看>>
bootstrap框架的使用
查看>>
POJ 3207 Ikki's Story IV - Panda's Trick
查看>>
JAVA_字节流类
查看>>
HTML5离线应用无法更新的定位与解决
查看>>
我是一个IT民工
查看>>
测试安全感
查看>>
简单的内存控制
查看>>
第十一次会议(5.28)
查看>>
org.tinygroup.templateengine-模板引擎
查看>>
SQL Access Advisor
查看>>
C# PDF Writer
查看>>
如何取未知Json字符串 某个主键取对应的Value
查看>>