« 検査入院してきました | メイン | PT2 on ubuntu10.04 »

javascriptでのCSV取り扱い

2012年04月10日

javascriptでのCSV取り扱い
[ Tips ]

javascriptでCSVを扱うと書いていますが、実際はjavascript encodeで、windows上でバッチファイル形式で走らせる時に遭遇したものです。

昔はDOS(windows)上で簡単なプログラムを走らせようとするとbatファイルを作るくらいしか無かった様に思います。
しかし現在は、JSE(javascript encode)や、WSH(Windows Script Host)、VBS(VBScript)等、簡単にプログラムを作ることができます。
中でもJSEはjavascriptそのものと言っていいので、使えるようにしておくと便利だと思います。

JSEを使い始めると、ファイルの取り扱い、CSVファイルを読み込んだり/書き込んだりして、各種のデータにアクセスすることが多くなると思います。
するとまず、CSVを読み込まなければならなくなりますが…
Googleで、javascript csvファイル読み込み等で検索すると、ファイルを読み込んで「,」(カンマ)で分割する方法が出てきます。
しかし、よくよくみてみるとここで出てくる「,」分割は、数値として「1,234」という様な数字があった場合、1と234に分割されてしまうコーディングだったりします。
正確には「"1,234"」の様にダブルコーテーションで括られているものは文字列として扱い、その中の「,」は分割しないという考慮をしなければなりません。
きちんとCSVの仕様を考慮してデータを読み込んでいる例を紹介しているサイトがすぐに見つかりません。
Google先生のクオリティの低下はやはり著しいのでしょうか。

さて、きちんとCSVの仕様を考慮しているサイトを紹介しておきましょう(すべてのサイトを検証した訳ではありませんので、動かない例もあるかもしれません。念のため)
Ask Ben: Parsing CSV Strings With Javascript Exec() Regular Expression Command

function CSVToArray( strData, strDelimiter ){
// Check to see if the delimiter is defined. If not,
// then default to comma.
strDelimiter = (strDelimiter || ",");

// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);


// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];

// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;


// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){

// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];

// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){

// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );

}


// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){

// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);

} else {

// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];

}


// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}

// Return the parsed data.
return( arrData );
}


PASTEBIN - parseCSV
function parseCSV(s,sep) {
// http://stackoverflow.com/questions/1155678/javascript-string-newline-character
var universalNewline = /\r\n|\r|\n/g;
var a = s.split(universalNewline);
for(var i in a){
for (var f = a[i].split(sep = sep || ","), x = f.length - 1, tl; x >= 0; x--) {
if (f[x].replace(/"\s+$/, '"').charAt(f[x].length - 1) == '"') {
if ((tl = f[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) == '"') {
f[x] = f[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
} else if (x) {
f.splice(x - 1, 2, [f[x - 1], f[x]].join(sep));
} else f = f.shift().split(sep).concat(f);
} else f[x].replace(/""/g, '"');
} a[i] = f;
}
return a
}


LiosK-free Blog - 続・正規表現を使ったCSVパーサ
function parseCSV2(text, delim) {
if (!delim) delim = ',';
var tokenizer = new RegExp(delim + '|\r?\n|[^' + delim + '"\r\n][^' + delim + '\r\n]*|"(?:[^"]|"")*"', 'g');

var record = 0, field = 0, data = [['']], qq = /""/g;
text.replace(/\r?\n$/, '').replace(tokenizer, function(token) {
switch (token) {
case delim:
data[record][++field] = '';
break;
case '\n': case '\r\n':
data[++record] = [''];
field = 0;
break;
default:
data[record][field] = (token.charAt(0) != '"') ? token : token.slice(1, -1).replace(qq, '"');
}
});

return data;
}


杉並WEB研究所(工事中) - JavaScriptでExcelのCSVを読み込む実験(カンマ対応版)
//CSVデータの配列化とHTML化処理
function parseText(str){
var resultText="<table border=1>";

//改行コードを変数にし分割処理をする
var CR = String.fromCharCode(13);
var LF = String.fromCharCode(10);
lineData = str.split(CR);
var ldLength = lineData.length;
var wqRank = new Array( ldLength);
for (var h=0; h<lineData.length; h++){
var wqCount = 0; var etcCount = 0;
var wqAnalyse = 0; var etcAnalyse = 0;
var wqArray = new Array();

//各行のダブルクォートの個数カウント
for (s=0; s<lineData[h].length; s++){
wqAnalyse = wqCount;
etcAnalyse = etcCount;
if (lineData[h].charAt(s) == "\""){
//ダブルクォートのカウントを1つ増やす
wqCount++;
} else {
//その他文字列のカウントを1つ増やす
etcCount++;
}
//連続してあるクォートを認識するための初期化処理
if ((wqAnalyse != wqCount) && (etcAnalyse == etcCount)){
etcCount = 0;
}
if ((wqAnalyse == wqCount) && (etcAnalyse != etcCount)){
wqCount = 0;
}
wqArray[s] = wqCount;
}

//Math.max関数でダブルクォートの最大値解析
wqRank[h] = Math.max.apply(Math,wqArray);
wqMaxCount = Math.max.apply(Math,wqRank);

//置換用にRegExpインスタンスを作成
for (l=1; l<=wqMaxCount; l++){
eval( "var repWq"+l+"= new RegExp('\"{"+l+",}','g');");
}
repWqRe = new RegExp('変換ダブルクォート',"g");
repCm = new RegExp('\,',"g");
repCmRe = new RegExp('変換カンマ',"g");

}

for (var i=0; i<lineData.length; i++){
//ダブルクォートの個数に応じて置換
matStr = lineData[i].replace(eval("repWq"+wqMaxCount),'\"');
for (var n=wqRank.length-1; n>=2; n--){
if (n != 2){
matStr = matStr.replace(eval("repWq"+wqRank[n]),'\"');
} else {
matStr = matStr.replace(repWq2,'変換ダブルクォート');
}
}

//正規表現で半角ダブルクォートに囲まれる文字列を取得
matStr = matStr.match(/"(\\["ntr\\]|[^"])*"|[^,]+/g);

//各文字列に含まれるカンマを「変換カンマ」に一時置換、その後半角ダブルクォートを取り除き、再びカンマで結合
for (var h=0; h<matStr.length; h++){
matStr[h] = matStr[h].replace(repCm,"変換カンマ");
matStr[h] = matStr[h].replace(repWq1,"");
lineData[i] = matStr.join();
}

//カンマで分割
strText = lineData[i].split(",");
resultText += "<tr>";

//HTMLのtableを繰り返し処理で作成し、セルにデータを入れていく
for (var j=0; j<strText.length; j++){

//変換カンマと変換ダブルクォートを元の半角に戻す
strText[j] = strText[j].replace(repCmRe,"\,");
strText[j] = strText[j].replace(repWqRe,"\"");
if (i < ldLength){
if(j == 0){
resultText += "<td>"+strText[j]+"</td>";
}
if(j == 1){
if (i == 0){
resultText += "<td>";
}else{
resultText += "<td><a href="+strText[j]+">";
}
}
if(j == 2){
if (i == 0){
resultText += strText[j]+"</td>";
}else{
resultText += strText[j] +"</a></td>";
}
}
}
}
resultText += "</tr>";
}
resultText += "</table>";
return resultText;
}

なお、私は行数も短い三番目の例を採用しました。

Posted by りじんぐ at 20:22

About

2012年04月10日 20:22に投稿されたエントリーのページです。

ひとつ前の投稿は「検査入院してきました」です。

次の投稿は「PT2 on ubuntu10.04」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type