JavaScript で文字列や日時フォーマットを自前でやる

思うところがあったのでやった。基礎練習とか素振りみたいなものです。

JavaScript の標準の文字列出力はあまりに貧弱すぎるからそこらへんなんとかなんないかやってみた。ライブラリを使うなら日時フォーマットについては Underscoe.String.js とかあるし、日時は Moment.js あたりがいいらしい。
Underscore.string
Moment.js | Parse, validate, manipulate, and display dates in javascript.

文字列の format

すごく単純な例

JavaScript テクニックバイブルにあったのを参考にした。

JavaScriptテクニックバイブル ~効率的な開発に役立つ150の技

JavaScriptテクニックバイブル ~効率的な開発に役立つ150の技

function pf() {
  var tmp = arguments[0];
  for (var i=1; i < arguments.length; i++) {
    tmp = tmp.replace(/%s/, arguments[i]);
  }
  return tmp;
}
pf("This %s is %s", "name", "ore")
// This name is ore

やってることは可変長引数をとってやって %s と決め打ちしたところを全部置換してるだけ。arguments[0] で元の文字列を受け取って for ループで i=1 以降を使うことで対応する。というやりかた。

もうちょっと拡張する - 自作

Python の "string".format(arg) をやってみた。で、似たようなことをやってるような人はそれなりにいたので結局だいぶ参考にしてしまったけど、まずは頭から消してどうにか自前でやってみた。あんまり String とかグローバルなところは拡張したくなかったけど、まあ、習作。

/**
 *     String.prototype.format
 * @param     String.prototype.arg
 */
String.prototype.format = function (arg) {

  // this = String
  var tmp = this;

  // Object
  if (typeof arg === "object"){
    for (var elem in arg){
      tmp = tmp.replace("{" + elem + "}", arg[elem]);
    }
    // String
  } else {
    for (var i=0; i < arguments.length; i++) {
      tmp = tmp.replace("{" + i + "}", arguments[i]);
    }
  }
  return tmp;
};
// オブジェクトで渡す
"abc {hoge} {moge}".format({hoge: "text1", moge: "text2"}))
// abc text1 text2
// 文字列を複数いれる
"abc {0} {1}".format("text1", "text2");
// abc text1 text2

これもわりと泥臭くて、結局文字列を愚直に組み立てて replace で置換してる。

もうちょっと拡張する - 参考資料

JavaScript で文字列フォーマットを実装してみた(sprintf もどき) | TM Life のままだけど、変数名はちょっとかえた

/**
 *     String.prototype.format2
 * @param     String.prototype.format2arg
 */
String.prototype.format2 = function (arg) {
  // init
  var func = null;

  // Object
  if (typeof arg === "object"){
    func = function (regexp, key) {return arg[key]; };
  }
  // String
  else{
    // 一度格納しないと末尾しか拾わない
    var args = arguments;
    func = function (regexp, key) {return args[key]; };
  }

  // this = String
  // replace の第2引数は関数でもよい!
  // そのとき return された文字列をつかう
  // g で繰り返しているから key が増えていく
  return this.replace(/\{(\w+)\}/g, func);
};

あたまいいなー。なにを知らなかったかというと、 string.repace の第2引数で関数がとれるということ。マッチした第一引数が regexp としてはいってきて、それを args[key] で置き換えてやる。ということをしている。

簡易日時フォーマット

けっこう泥臭いものをつくった。そのかわり、上で自作した string.format 関数をつかった

/**
 * strftime
 * @param d
 */
function strftime(d) {
  var date_format = "{0}年{1}月{2}日:{3}時{4}分{5}秒".format(
    d.getFullYear(),
    d.getMonth() < 10 ? "0" + d.getMonth() : d.getMonth(),
    d.getDate()  < 10 ? "0" + d.getDate() : d.getDate(),
    d.getHours() < 10 ? "0" + d.getHours() : d.getHours(),
    d.getMinutes() < 10 ? "0" + d.getMinutes() : d.getMinutes(),
    d.getSeconds() < 10 ? "0" + d.getSeconds() : d.getSeconds()
  );
  return date_format;
}
// strftime(new Date()))
// "2012年01月02日:03時04分05秒"

いいかんじです

まあ

素振りです。JS の標準機能が貧弱すぎるなら、自分で武器を作れるようにならなくてはいけない。