2012-01-23 59 views
4

首先快速定義:)模板和佔位算法

  • 模板 - 其可以包含佔位符(示例: 「你好[名稱]」)的字符串 - 甲子whitin
  • 佔位符方括號(例如: 「姓名」 的「hello [名稱] :)
  • 屬性映射 - 與串A有效的對象作爲值

我需要編寫一個代碼,用屬性映射中的匹配值替換佔位符(以及括號)。

例如: 以下屬性映射:

{ 
    "name":"world", 
    "my":"beautiful", 
    "a":"[b]", 
    "b":"c", 
    "c":"my" 
} 

預期結果:

  • 「你好名」 - > 「你好名」

  • 「你好[名稱] 「 - >」你好世界「

  • 」[b]「 - >」c「

  • 「[1]」 - > 「C」(因爲並[a] - >並[b] - >並[c])

  • 「[[B]]」 - > 「我的」(因爲[[b] - > [C] - >我)

  • 「你好[我] [名]」 - > 「你好美麗的世界」

+0

如果出現循環,會發生什麼情況,如 - > [b]和b - > [a]?另外,所有的決定都是強制的(也就是說,沒有多個值的關鍵映射?) – templatetypedef

+0

當然,忽略循環。考慮地圖對象有效 –

回答

2
var map = { 
    "name":"world", 
    "my":"beautiful", 
    "a":"[b]", 
    "b":"c", 
    "c":"my" 
}; 

var str = "hello [my] [name] [[b]]"; 

do { 
    var strBeforeReplace = str; 
    for (var k in map) { 
     if (!map.hasOwnProperty(k)) continue; 
     var needle = "[" + k + "]"; 
     str = str.replace(needle, map[k]); 
    } 
    var strChanged = str !== strBeforeReplace; 
} while (strChanged); 

document.write(str); //hello beautiful world my 
+0

優秀!,這正是我需要的! 非常感謝你 –

2

的由@克里斯答案是非常好的,我只是想提供一個使用正則表達式的替代解決方案,「反過來」,即不是通過廁所國王爲屬性映射中所有項目的「佔位符版本」發生,但通過重複查找佔位符本身的出現,並用屬性映射中的相應值替換它。這有兩個好處:

  1. 如果物業地圖變得非常大,這個解決方案應該有 更好的表現(有待雖然基準)。
  2. 通過調整正則表達式和替換函數(這裏可能不是問題),可以很容易地修改佔位符和方式替換工作。

的缺點是,當然,該代碼是稍微複雜一點(部分是由於JavaScript的缺乏代正則表達式匹配使用自定義功能的一個很好的方式,所以這就是substituteRegExp是事實):

function substituteRegExp(string, regexp, f) { 
    // substitute all matches of regexp in string with the value 
    // returned by f given a match and the corresponding group values 
    var found; 
    var lastIndex = 0; 
    var result = ""; 
    while (found = regexp.exec(string)) { 
     var subst = f.apply(this, found); 
     result += string.slice(lastIndex, found.index) + subst; 
     lastIndex = found.index + found[0].length; 
    } 
    result += string.slice(lastIndex); 
    return result; 
} 

function templateReplace(string, values) { 
    // repeatedly substitute [key] placeholders in string by values[key] 
    var placeholder = /\[([a-zA-Z0-9]+)\]/g; 
    while (true) { 
     var newString = substituteRegExp(string, placeholder, function(match, key) { 
      return values[key]; 
     }); 
     if (newString == string) 
      break; 
     string = newString; 
    } 
    return string; 
} 

alert(templateReplace("hello [[b]] [my] [name]", { 
    "name":"world", 
    "my":"beautiful", 
    "a":"[b]", 
    "b":"c", 
    "c":"my" 
})); // -> "hello my beautiful world" 

更新:我做了一些小的剖析兩個解決方案比較(在的jsfiddle http://jsfiddle.net/n8Fyv/1/,我也用螢火蟲)。雖然@chris的解決方案對於小字符串更快(不需要解析正則表達式等),但這種解決方案對大字符串(成千上萬個字符的順序)執行得更好。我沒有比較不同大小的房產地圖,但預計會有更大的差異。

在理論上,這種解決方案具有運行時間爲O(ķÑ)其中ķ是佔位符的嵌套和Ñ的深度是字符串的長度(假設字典/哈希查找需要一定的時間),而@克里斯溶液是O(ķñ米)其中是在屬性映射的項目數。當然,所有這些只與大量輸入有關。

+0

謝謝,這真是精心製作! –

0

如果你對.NET的String.Format很熟悉,那麼你應該看看this JavaScript implementation。它也支持數字格式,就像String.Format一樣。

這裏有一個如何使用它的一個例子:

var result = String.Format("Hello {my} {name}", map); 

然而,這將需要一些修改做遞歸模板。

+0

謝謝我會看看:) –