最近更新: 2015-11-10

JavaScript print format

在 C 語言中, printf 是一個很方便的輸出函數,在其他程式語言中,也或多或少提供了類似的格式化輸出或是格式化字串功能。 不過 JavaScript 並沒有定義這種函數 (直到 ECMAScript6 才提供 template string),那就自己寫吧。本文說明兩種格式化字串的實作方式。

我直接把格式化函數加到 String 類別中,讓它們變成字串方法。 這樣就可以 "Hello {0}!".interpolate('rock') 的形式撰寫。 這種敘述方式符合多數 OOPL 的表達方法。

第一個方法是用 {n} 包覆要代入的內容,基數從 0 開始。 這是 C# 式的用法。

/**
A method of String: "format".interpolate(...);
by {0}, {1}, {2}, ... base from 0.
 */
String.prototype.interpolate = function()
{
    if (arguments.length < 1) // do nothing
        return this;

    var s = this;
    var args = arguments;
    // see ECMA-262 3rd edition, 15.5.4.11 String.prototype.replace.

    return s.replace(/\{\d+\}/g, function(matched, offset, src) {
        var k = matched.substring(1,matched.length-1); // index base from 0.

        return (args[k] ? args[k] : matched);
    });
}

第二個方法是用 $n 標示要代入的內容,基數從 1 開始。 這比較像 shell script 的用法。

/**
A method of String: "format".interpolate(...);
by $1, $2, ... base from 1.
 */
String.prototype.interpolate2 = function()
{
    var s = this;
    var index_offset = 1; // index base from 1.

    if (this instanceof String) {
        if (arguments.length < 1) // nothing
            return this;
    }
    else {
        s = arguments[0]; // notice: arguments is not an array.

        index_offset = 0;
        if (arguments.length < 2) /// nothing
            return s;
    }

    var args = arguments;
    return s.replace(/\$[\$\d]+/g, function(matched, offset, src) {
        var k = parseInt(matched.substring(1)) - index_offset;
        return (args[k] ? args[k] : matched);
    });
}

使用如下例。

alert("nothing".interpolate());

// 這是 C# 式的用法。基數從0開始。
alert("hello {0}. {1} + {2} = {3}".interpolate("abc{2}", 'two', 3, 5));

// 這比較像 shell script 的用法,基數從1開始。
alert("hello $1. $2 + $3 = $4".interpolate2("abc$2", 'two', 3, 5));

注意我操作 replace() 的方法,必須要這樣做,才不會重複替換已經代入的內容。 如果以參數清單做迭代,每次都替換整個字串的話,像上例 "abc{2}" 這種情形就會被再次替換內容,導致非預期結果。

JavaScript 雖然沒有正式的格式化字串或輸出函數,但是非正式的 console 項目卻實作了格式化功能。可惜的是 console 只能用於輸出內容。參考「JavaScript console」。
相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/25899028.html

樂多舊回應
未留名 (#comment-23754988)
Fri, 29 Nov 2013 17:20:30 +0800
全域變數 k應該是意外 :p
未留名 (#comment-23755062)
Fri, 29 Nov 2013 17:44:54 +0800
嗯,確實忘了在 k 前面加個 var 。
幸好 i,j,k,v 我都用在小區塊,侷限了影嚮區域,沒對我造成非預期錯誤。