N88-BASIC への布石?(今のスキルでは無理)テーブルを弄る、その6?(構文解析が主題なのにそこが判らない)
.sort は、OK!
.filter が難問、未実装。(これから)
> table.filter('(個数 > 10 & 色 = lime) | 個数 < 5')
<!DOCTYPE html> <title></title> <table> <tr> <th>String <th>Type <th>Number <tr> <th>ABC <td>001 <td>123 <tr> <th>DEF <td>003 <td>456 <tr> <th>GHI <td>002 <td>789 <tr> <th>JKL <td>002 <td>012 <tr> <th>MNO <td>003 <td>345 <tr> <th>PQR <td>001 <td>678 </table> <script> (function () { function TDC (table, useHeader) { this.table = table; this.useHeader = !! useHeader; } //_________________ function sort (arg) { var parm; var order = []; var cells; var hash = { }; var i, max, key, cmd; var p, d, h; var rows = [], _rows; switch (true) { //全てを昇順 case (1 > arguments.length || '*' === arg) : max = this.table.rows[0].cells.length; for (i = 0; i < max; i++) order[i] = { 'direction': true, 'cellIndex': i }; // true = 降順 break; // 第一行の各セル値を配列にする case (this.useHeader) : parm = arg.split (/\s*;\s*/g); cells = this.table.rows[0].cells; for (i = 0, max = cells.length; i < max; i++) { key = cells[i].textContent.replace (/^\s+|\s+$/g, ''); if ('' == key || hash.hasOwnProperty (key)) { alert ('ヘッダ行の値が不正です'); throw new Error; } hash[ key ] = i; } for (i = 0, max = parm.length; i < max; i++) { if (parm[i]) { p = /^([-+])?(.*)$/.exec (parm[i]); if (! hash.hasOwnProperty (p[2])) { alert ('ソートするヘッダ行の値がありません'); throw new Error; } order[i] = { 'direction': ('-' !== p[1]) , 'cellIndex': hash[p[2]] }; } } break; // 第一行をデータ行とみなす default : parm = arg.split (/;/g); for (i = 0, max = parm.length; i < max; i++) { p = /^([-+])?column(\d+)$/i.exec (parm[i]); if (! p) { alert ('ヘッダ行の値が不正です2'); throw new Error; } order[i] = { 'direction': ('-' !== p[1]), 'cellIndex': Number (p[2]) }; } } // sort _rows = this.table.rows; for (i = this.useHeader ? 1: 0, max = _rows.length; i < max; i++) rows.push (_rows[i]); rows.sort (compareFunc (order)); } // 並び替える function compareFunc (order) { var max = order.length; return function (a, b) { var i; var _a, _b, f; var idx; for (i = 0; i < max; i++) { idx = order[i].cellIndex; _a = a.cells[ idx ].textContent; _b = b.cells[ idx ].textContent; if (isNaN (_a) || isNaN (_b)) { ; } else { _a = Number (_a); _b = Number (_b); } if ((f = (_a > _b) - (_a < _b))) { if (order[i].direction) f = -f; if (-1 === f) a.parentNode.insertBefore (b, a); return f; } continue; } return 0; }; } function create (table, useHeader) { if ('TABLE' !== table.nodeName) { return null; } return new TDC (table, useHeader); } //_________________ TDC.prototype.sort = sort; this.createTDC = create; })(); var table = createTDC (document.querySelector ('table'), true); table.sort ('-Type ; Number ;'); </script>
JavaScript version 1.8
<!DOCTYPE html> <title></title> <table> <tr> <th>String <th>Type <th>Number <tr> <th>DEF <td>003 <td>456 <tr> <th>ABC <td>001 <td>123 <tr> <th>GHI <td>002 <td>789 <tr> <th>JKL <td>002 <td>012 <tr> <th>MNO <td>003 <td>345 <tr> <th>PQR <td>001 <td>678 <tr> <th>ABC <td>001 <td>121 <tr> <th>ABC <td>002 <td>120 </table> <script type="application/javascript; version=1.8"> (function () { function TDC (table, useHeader) { this.table = table; this.useHeader = !! useHeader; } //_________________ const A = Array.prototype; const reg = (function () { let spc = '\\s\*'; let dir = '\\-|\\+'; let all = '\\*'; let cln = ';'; let num = '[0-9]\+'; return { 'all' : new RegExp ('^'+ spc +'('+ dir +')?('+ all +')'+ spc +'$'), 'split' : new RegExp (spc + cln + spc, 'g'), 'column' : new RegExp ('^'+ spc +'?('+ dir +')?column('+ num +')'+ spc + '$'), 'name' : new RegExp ('^'+ spc +'?('+ dir +')?(.*)'+ spc + '$') }; })(); const getHash = (function (get) (function (row) A.reduce.call (row.cells, get, { }))) (function (r, c, i) let (t = c.textContent.trim ()) t ? (r[t] = i, r) : r); //全ての列をソート対象 const orderAll = (function (get) (function (row, dir) A.map.call (row.cells, get, dir))) (function (_, i) ({ 'direction': this, 'cellIndex': i })); //([-+])?column(\d) const orderHeaderColumn = (function (r, a, i) let ([c, d, n] = reg.column.exec (a)) c ? r.concat ({ 'direction': ('-' !== d) , 'cellIndex': Number (n) }) : r); //([-+])?name const orderHeaderName = (function (hash) (function (r, a, i) let ([_, d, k] = reg.name.exec (a)) (k in hash) ? r.concat ({ 'direction': ('-' !== d) , 'cellIndex': hash[k] }) : r)); const sort = (function (arg) { let o; let order; switch (true) { //全ての列をソート対象にする case (1 > arguments.length) : case (!! (o = reg.all.exec (arg))) : order = orderAll (this.table.rows[0], ('-' !== o[1])); break; // 第一行の各セル値を配列にする case (this.useHeader) : order = arg.split (reg.split) .reduce (orderHeaderName (getHash (this.table.rows[0])), []); break; // 全行をデータ行とみなす default : order = arg.split (reg.split) .reduce (orderHeaderColumn, []); break; } // sort A.slice.call (this.table.rows, this.useHeader * 1) .sort (compareFunc (order)); return this; }); // 並び替える const compareFunc = function (order) { var max = order.length; if (1 > max) throw new Error; return function (a, b) { var i; var _a, _b, f; var idx; for (i = 0; i < max; i++) { idx = order[i].cellIndex; _a = a.cells[ idx ].textContent.trim (); _b = b.cells[ idx ].textContent.trim (); if (isNaN (_a) || isNaN (_b)) { ; } else { _a = Number (_a); _b = Number (_b); } if ((f = (_a > _b) - (_a < _b))) { if (! order[i].direction) f = -f; if (1 === f) a.parentNode.insertBefore (b, a); return f; } } return 0; }; } const filter = (function (cond) { A.slice.call (this.table.rows, this.useHeader * 1) .forEach (); return this; }); //_________________ const create = (function (table, useHeader) ('TABLE' === table.nodeName) ? new TDC (table, useHeader) : null); //_________________ TDC.prototype.sort = sort; TDC.prototype.filter = filter; //_________________ this.createTDC = create; })(); var table = createTDC (document.querySelector ('table'), true); var s; s = ['*', '-String', 'Type;-Number;', '-Number;;']; s.forEach (function (s) (table.sort (s), alert(s))); table.useHeader = false; ['*','-column1'].forEach (function (s) (table.sort (s), alert(s))); </script>