1 /**
   2     @name String
   3     @class Additions to the core string object.
   4 */
   5 
   6 /**
   7  * 文字列の両端にある空白文字(スペースや改行)を除去した文字列を返します。
   8  * @return {String} 処理された文字列
   9  * @author Steven Levithan, released as public domain.
  10  */
  11 String.prototype.trim = function() {
  12     var str = this.replace(/^\s+/, '');
  13     for (var i = str.length - 1; i >= 0; i--) {
  14         if (/\S/.test(str.charAt(i))) {
  15             str = str.substring(0, i + 1);
  16             break;
  17         }
  18     }
  19     return str;
  20 }
  21 /*t:
  22     plan(6, "Testing String.prototype.trim.");
  23     
  24     var s = "   a bc   ".trim();
  25     is(s, "a bc", "multiple spaces front and back are trimmed.");
  26 
  27     s = "a bc\n\n".trim();
  28     is(s, "a bc", "newlines only in back are trimmed.");
  29     
  30     s = "\ta bc".trim();
  31     is(s, "a bc", "tabs only in front are trimmed.");
  32     
  33     s = "\n \t".trim();
  34     is(s, "", "an all-space string is trimmed to empty.");
  35     
  36     s = "a b\nc".trim();
  37     is(s, "a b\nc", "a string with no spaces in front or back is trimmed to itself.");
  38     
  39     s = "".trim();
  40     is(s, "", "an empty string is trimmed to empty.");
  41 
  42 */
  43 
  44 /**
  45  * この文字列中で開始文字openと終了文字closeに囲まれる範囲を最大マッチで検索し、文字インデックス番号として返します。
  46  * @param {String} open  開始文字
  47  * @param {String} close 終了文字
  48  * @return {Number[]} マッチング範囲を表す数値配列。インデックス0が開始文字の番号を、インデックス1が終了文字の番号を表します。
  49  *                    文字が見つからないなど範囲を確定できなかった場合、戻り値の番号には全て-1が設定されます。 
  50  */
  51 String.prototype.balance = function(open, close) {
  52     var i = 0;
  53     while (this.charAt(i) != open) {
  54         if (i == this.length) return [-1, -1];
  55         i++;
  56     }
  57     
  58     var j = i+1;
  59     var balance = 1;
  60     while (j < this.length) {
  61         if (this.charAt(j) == open) balance++;
  62         if (this.charAt(j) == close) balance--;
  63         if (balance == 0) break;
  64         j++;
  65         if (j == this.length) return [-1, -1];
  66     }
  67     
  68     return [i, j];
  69 }
  70 /*t:
  71     plan(16, "Testing String.prototype.balance.");
  72     
  73     var s = "{abc}".balance("{","}");
  74     is(s[0], 0, "opener in first is found.");
  75     is(s[1], 4, "closer in last is found.");
  76     
  77     s = "ab{c}de".balance("{","}");
  78     is(s[0], 2, "opener in middle is found.");
  79     is(s[1], 4, "closer in middle is found.");
  80     
  81     s = "a{b{c}de}f".balance("{","}");
  82     is(s[0], 1, "nested opener is found.");
  83     is(s[1], 8, "nested closer is found.");
  84     
  85     s = "{}".balance("{","}");
  86     is(s[0], 0, "opener with no content is found.");
  87     is(s[1], 1, "closer with no content is found.");
  88     
  89     s = "".balance("{","}");
  90     is(s[0], -1, "empty string opener is -1.");
  91     is(s[1], -1, "empty string closer is -1.");
  92     
  93     s = "{abc".balance("{","}");
  94     is(s[0], -1, "opener with no closer returns -1.");
  95     is(s[1], -1, "no closer returns -1.");
  96     
  97     s = "abc".balance("{","}");
  98     is(s[0], -1, "no opener or closer returns -1 for opener.");
  99     is(s[1], -1, "no opener or closer returns -1 for closer.");
 100     
 101     s = "a<bc}de".balance("<","}");
 102     is(s[0], 1, "unmatching opener is found.");
 103     is(s[1], 4, "unmatching closer is found.");
 104 */