String.prototype.format
String.prototype.format = (function(regx, zero){ return function(){ var args = arguments, x = 0; return this.replace(regx, function(_, pos_s, flag, width, pos_w, prec, pos_p, type){ if(type == '%') return '%'; if(~width.indexOf('*')) width = pos_w > 0 ? args[pos_w - 1] : args[x++]; prec = prec === undefined ? -1 : ~prec.indexOf('*') ? (pos_p > 0 ? args[pos_p - 1] : args[x++]) : +prec; var r = '', a = pos_s > 0 ? args[pos_s - 1] : args[x++], sharp = ~flag.indexOf('#'); var sign = a < 0 && (a *= -1) ? '-' : ~flag.indexOf('+') ? '+' : ~flag.indexOf(' ') ? ' ' : ''; switch(type){ case 'd': case 'i': r = !r && prec == 0 ? '' : sign + zero(''+ (a | 0), prec); break; case 'u': a = sign == '-' ? (sign = '', 0x100000000 - (a | 0)) : a | 0; r = sign + zero(''+ a, prec); break; case 'b': case 'B': r = sign + (sharp ? '0b' : '') + zero((+a).toString(2), prec); break; case 'o': case 'O': r = sign + (sharp ? '0' : '') + zero((+a).toString(8), prec); break; case 'x': case 'X': r = sign + (sharp ? '0x' : '') + zero((+a).toString(16), prec); break; case 'f': case 'F': r = sign + (+a).toFixed(~prec ? prec : 6); if(!prec && sharp) r += '.'; break; case 'e': case 'E': r = sign + (+a).toExponential(~prec ? prec : 6); if(!prec && sharp) r = r.replace(/e/, '.e'); break; case 'g': case 'G': r = sign + (+a).toPrecision(~prec ? prec : 6); if(!sharp) r = r.replace(/\.?0+(?=e|$)/, ''); break; case 'a': case 'A': r = sign + (+a).toString(16); if(~prec) r = r.replace(/([^.]+)\.?([^\(]*)(.*)/, function(_, i,d,e){ return i + (prec ? '.'+ (d +'0000000000000').substr(0, prec) + e : sharp ? '.' : '') }); break; case 'c': r = String.fromCharCode(a | 0); break; case 'p': if(typeof uneval == 'function') a = uneval(a); // fallthrough case 's': r = ~prec ? a.substr(0, prec) : a; break; } if(/[BXEGA]/.test(type)) r = r.toUpperCase(); if((width -= r.length) > 0){ var t = Array(width + 1).join(~flag.indexOf(0) && /[^cs]/.test(type) ? 0 : ' '); r = ~flag.indexOf('-') ? r + t : t + r; } return r; }); }; })( /%(?:(\d+)\$)?([-+ #0]*)(\d*|\*(?:(\d+)\$)?)(?:\.(\d+|\*(?:(\d+)\$)?))?([diubBoOxXeEfFgGaAcsp%])/g, function(s, p){ return (p -= s.length) > 0 ? Array(p + 1).join(0) + s : s } );
どう書くに投稿した sprintf がベース。Life is beautiful: Javascript、クロージャを使ったプライベート関数の隠蔽についてを参考にオブジェクトをキャッシュしてみたが,効果の程は不明。
- 既知の問題:
- "%#010b".format(10) が "0b00001010" でなく "00000b1010" になる。"%#10.8b".format(10) とする必要あり。