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>

被災者証明

ニュースで、震災&津波の影響を受けない盛岡市が、停電でも被災者証明を出すと報じられた。それをうけ、青森県八戸市が、住民全員に証明書を出す用意があると、次の日のニュース。その次に八戸市の周辺の市町村もそれに追従。そして我が洋野町も追従。
停電だけで被災者証明?とも思うけど、頂ける者なので、頂いて来た。

それでも、津波の被害を受けた町には行きたくない。なぜなら、沢山の浮遊霊が私を見るから。