忙しくする毎日
実質¥38,000の義足が新調された。なかなか足に合わない。
それなのに、テントの倉庫の屋根に上り破れたテントを補修する。
集成材のカットと購入してから1カ月、運送会社のトラブルにより香川県と3往復した模様。
やっと届いた材料で仕事で使う机を2つ製作する
夜は、勉強する
<!DOCTYPE html> <meta charset="utf-8"> <title>テCSVファイルに関連したもの</title> <style> section, li { width:60em; line-height :150%;} section { padding-bottom:3em; border-bottom: 2px #4d4 dotted; } #SAMPLE_TABLE thead { background: #080; color:#ff0; } #SAMPLE_TABLE tbody tr { background:#f8f8f8; } #SAMPLE_TABLE tbody tr:nth-child(even){ background:#eef; } #SAMPLE_TABLE tbody td:nth-child(1){ background:#3a3; color: #FFF; text-align: center; } #SAMPLE_TABLE td { padding : 0 .3em; } code { white-space: pre-wrap; } </style> <body> <h1>CSVファイルに関連したものをライブラリ化できる?</h1> <ol> <li> <a href="#SECTION-1">CSVファイルの一般的書式</a> <li> <a href="#SECTION-2">CSVファイルのサンプル</a> <li> <a href="#SECTION-3">ライブライ化で、目標とするもの</a> </ol> <section id="SECTION-1"> <h2>CSVファイルの一般的書式</h2> <p> <a href="http://www.ietf.org/rfc/rfc4180.txt">原文</a>は、英語なので <a href="http://www.kasai.fm/wiki/rfc4180jp">邦訳</a> (<a href="http://www.kasai.fm/">アルプス登山の玄関口笠井家</a>)を参照の事。 <p> MIMEタイプ は、弄らないので略して引用する。 <ul> <li> 各レコードは、改行(CRLF)を区切りとする、分割された行に配置される。 <li> ファイル末尾のレコードの終端には、改行はあってもなくてもよい。 <li> ファイルの先頭には、オプションとして、通常行と同一の書式を持つ、 ヘッダ行が存在してもよい。このヘッダは、ファイル中の各フィールドの名称を保持し、 ファイルの残りの部分にある各レコードが持っているのと、同じ数のフィールドを 持つべきである。 <li> ヘッダと各レコードは、コンマで区切られた、一つ以上のフィールドを含む。 各行が保持するフィールドの数は、ファイル全体を通じ、同一であるべきである。 スペースは、フィールドの一部とみなす。無視すべきではない。 最後のフィールドは、コンマで終わってはならない。 <li> (レコード中の) 各フィールドは、それぞれダブルクォーテーションで囲んでも 囲わなくてもよい。 フィールドがダブルクォーテーションで囲まれていない場合、そのフィールドの値には、 ダブルクォーテーションが含まれてはいけない。 <li> 改行(CRLF)、ダブルクォーテーション、カンマを含むフィールドは、ダブルクォーテーションで 囲むべきである。 <li> フィールドがダブルクォーテーションで囲まれている場合、フィールドの値に含まれる ダブルクォーテーションは、その直前にひとつダブルクォーテーションを付加して、 エスケープしなければならない。 </ol> </section> <section id="SECTION-2"> <h2>サンプルとするCSV文字列</h2> <div> <textarea cols="60" rows="10" id="SAMPLE_CSV"> ID,氏名,シメイ,性別,電話番号,生年月日,年齢,血液型 1,椎名和代,シイナカズヨ,女,0312581924,1959/08/27,51,O 2,村井博文,ムライヒロフミ,男,0382192989,1985/01/14,26,AB 3,西川俊子,ニシカワトシコ,女,0343460909,1971/10/03,39,B 4,黒田睦美,クロダムツミ,女,0315211328,1977/11/11,33,O 5,五十嵐颯,イガラシソウ,男,0335494621,1974/02/11,37,O 6,小池真理子,コイケマリコ,女,0320317992,1969/11/10,41,AB 7,久保宏美,クボヒロミ,女,0330062953,1955/11/05,55,O 8,岩永音葉,イワナガオトハ,女,0348956804,1958/02/07,53,A 9,庄司貞次,ショウジテイジ,男,0355093904,1962/10/19,48,A 10,赤塚綾菜,アカツカアヤナ,女,0399960433,1954/05/07,57,A 11,杉野茂,スギノシゲル,男,0302024645,1964/11/22,46,A 12,北原紗耶,キタハラサヤ,女,0380462601,1974/05/11,37,AB 13,福永孝二,フクナガコウジ,男,0333378739,1972/05/07,39,O 14,増井武彦,マスイタケヒコ,男,0382039671,1964/08/22,46,A 15,新谷悦代,アラヤエツヨ,女,0377460694,1987/08/06,23,A 16,小野寺忠三,オノデラチュウゾウ,男,0305429745,1951/08/11,59,B 17,富山葉菜,トミヤマハナ,女,0312582616,1982/12/27,28,O 18,森谷一寿,モリヤカズヒサ,男,0348789450,1979/12/18,31,A 19,妹尾空,セノオソラ,女,0322594281,1962/07/03,48,O 20,塚本重樹,ツカモトシゲキ,男,0325976517,1961/11/26,49,A 21,島友子,シマトモコ,女,0327032866,1962/09/07,48,A 22,河上照夫,カワカミテルオ,男,0378647656,1968/05/31,43,A 23,玉木香織,タマギカオリ,女,0319236941,1984/09/18,26,O 24,小倉孝之,オグラタカユキ,男,0328378613,1990/06/27,21,O 25,狩野重雄,カノウシゲオ,男,0305641486,1958/01/18,53,O 26,坂田可憐,サカタカレン,女,0338182032,1986/06/10,25,O 27,海老原正男,エビハラマサオ,男,0330037767,1963/06/29,47,B 28,富山彩花,トミヤマアヤカ,女,0345313806,1964/05/29,47,A 29,石田義和,イシダヨシカズ,男,0352023930,1961/04/25,50,AB 30,小野寺聖子,オノデラセイコ,女,0355404261,1972/06/04,39,O </textarea> </div> <p> もちろん<a href="http://domes.lingua.heliohost.org/libxml-js/src-test/jsom/tdc.html">ここ</a>からコピペ </section> <section id="SECTION-3"> <h2>ライブライ化で、目標とするもの</h2> <pre> C$V(table) ・table が Array ならそのまま返す。 ・table が String(CSV ソース)なら Array 化して返す。 ・table が HTMLTableElement なら Array 化して返す。 C$V(table, query) ・上記に加え、query を適用した Array を返す。 ・query は { select:..., where:..., order:... } のようなメンバを持つ Object。 // 例:男性か、二十歳以下の女性のレコードを、男女順および年齢の高い順に並べ替えた上で、 名前と給料の列を取得し、給料の総額を出す。 C$V(table, { select: '名前, 給料', where: '性別 = 男性 | (性別 <= 20 & 性別 = 女性)', order: '+性別; -年齢' }).reduce(function (sum, row) { return sum + row[1]; }); </pre> </section> <sction id="SECTION-4"> <h2>操作されるテーブル</h2> <table border="1" id="SAMPLE_TABLE"> <tr> <th>a <td>b <td>c <tr> <th>d <td>e <td>f </table> </section> <section id="SECTION-5"> <h2>JavaScriptのコード</h2> <code id="CODE" class="JavaScript"> </code> </section> <script> (function () { // csvを解析するための関数群 function trim (str) {//先端と終端の改行を取り除く return String (str).replace (/^[\r\n]+|[\r\n]+$/g, ''); } //以下の関数 isStrict、isLoose は、CSVを厳格にするための関数 //(「英語圏の文字だけを利用するか?」の意の厳格ではない。) //条件によりに「判断する関数」を代入し、それらに任せている。 //(「関数は呼び出しコストが高い」との意で、自分的に頻繁に使わない技法。 // 読みやすさと生産性とならこの書き方→見習う //各行のフィールドの数が同じでない場合、それを弾く。 function isStrict (flength, findex) { return flength === findex; } //引数も渡されるが無視 function isLoose () { return true; } //CSV文字列を配列に function csvToAry (stringData, strict, separator) { //初期値の代入と区切り文字の判別を行う→見習う if ((separator || (separator = ',')) === ',' || separator === '\t') { var isWellFormed = strict ? isStrict : isLoose; var pattern = new RegExp ('^(?:' + separator + // ,で始まるか? '|(?:\\r\\n|\\r|\\n)' + // 改行文字か? '|"(?:""|[^"])*"' + '|[^\\r\\n"' + separator + '][^\\r\\n' + separator + ']*' + ')'); var flength = 0; //フィールドの数 var findex = 0; //現行のフィールド数 var fields = [ '' ]; var records = [ fields ]; //戻り値 var token; //切り出した文字 for ( //前後の改行を取り除く stringData = trim (stringData); //トークンの判定(配列成功)と変数の上書き→見習う (token = pattern.exec (stringData)) && (token = token[0]); //トークンの次の文字を対象とする stringData = stringData.slice (token.length) ) { switch (token.charAt (0)) {//切り出されたトークンの先頭の文字で今後判断する case separator : fields[++findex] = ''; // セパレータが現れる度、次のフィールドを初期化 break; case '\r' ://「\r\n」は、正規表現で2文字で切り出しているが最初の1文字判定でOK! case '\n' : if (! isWellFormed (flength || (flength = findex), findex)) throw new Error ('malformed CSV.'); fields = records[records.length] = [''];//改行なので次を初期化 findex = 0; break; case '"' : //「”」で始まると「”」で終わるはずなので中抜きする、 //さらに連続した「""」は、「"」とする fields[findex] = token.slice (1, -1).replace (/""/g, '"'); break; default : fields[findex] = token; break; } } //切り出す文字が無い、(各行のフィールド数がすべて同じなら) if (stringData === '' && isWellFormed (flength, findex)) { return records; } } throw new Error ('malformed CSV.'); } //__________ // HTMLTableElementを配列化する関数群 function getTextByCell (cell) {//セルのテキスト取得 return cell.textContent.trim ();//空白を無視する? } function getCells (row) {// 行のセルを取得 return [].map.call (row.cells, getTextByCell); } function tableToAry (table) {// trを走査 return [].map.call (table.rows, getCells); } //__________ //本体 function C$V (table, query) { if (1 > arguments.length) return null; var ary; // [ ]; switch (true) { case Array.isArray (table) : ary = table; break; case 'string' === typeof (table): ary = csvToAry (table); break; case table instanceof HTMLTableElement: ary = tableToAry (table); break; default : throw new Error ('無効な引数') } return ary; } //____ this.C$V = C$V; }) (); // 配列をテーブルにする (function () { function insertTD (text) { this.insertCell (-1).textContent = text; } function insertTR (record) { record.forEach (insertTD, this.insertRow (-1)); } function setTableSectionElement (ary) { ary.forEach (insertTR, this); } function ary2Table (ary, table, allTbody) { if (2 > arguments.length) throw new Error (); if (! Array.isArray (ary)) throw new Error ('Not Array'); if (! table instanceof HTMLTableElement) throw new Error ('Not HTMLTableElement'); while (table.hasChildNodes ()) table.removeChild (table.firstChild); if (! allTbody) setTableSectionElement.call (table.createTHead (), ary.splice (0,1)); setTableSectionElement.call (table.createTBody (), ary); } this.ary2Table = ary2Table; }) (); //______________________ //もともとあるテーブルから配列に alert(C$V (document.getElementById ('SAMPLE_TABLE')).join("\n")); //CSV文字列を配列にしてテーブルに ary2Table ( C$V (document.getElementById ('SAMPLE_CSV').value), document.getElementById ('SAMPLE_TABLE') ); </script> <script> document.getElementById ('CODE').textContent = document.querySelector ('script').textContent; </script>