我精心製作了下面的函數,它支持尾字母,前導零...(參看下面的例子):
function cmpVersions(a, b) {
var partsA = a.split('.');
var partsB = b.split('.');
var nbParts = Math.max(partsA.length, partsB.length);
for (var i = 0; i < nbParts; ++i) {
if (partsA[i] === undefined) {
partsA[i] = '0';
}
if (partsB[i] === undefined) {
partsB[i] = '0';
}
// edit: added this part
// - fixes the important case "1.2/1.10"
// - but breaks the not-so-important case "1.02/1.1"
var intA = parseInt(partsA[i], 10);
var intB = parseInt(partsB[i], 10);
if (!isNaN(intA) && !isNaN(intB)) {
if (intA > intB) {
return 1;
} else if (intA < intB) {
return -1;
}
}
var compare = partsA[i].localeCompare(partsB[i]);
if (compare !== 0) {
return compare;
}
}
return 0;
}
所以,舉幾個例子:
// trailing letters
cmpVersion('1.0a', '1.0b'); // -1
// leading zeroes
cmpVersion('1.01', '1.1'); // -1
// "zero" parts
cmpVersion('1', '1.0'); // 0
如果你不不需要支持前導零,這裏是一個更簡單的替代方案:
function cmpVersions(a, b) {
function padParts(version) {
return version
.split('.')
.map(function (part) {
return '00000000'.substr(0, 8 - part.length) + part;
})
.join('.');
}
a = padParts(a);
b = padParts(b);
return a.localeCompare(b);
}
快速更新:後來我注意到第一個函數在「1.10」之前排序「1.2」,這是公然錯誤的。此外,「重要的前導零」是棘手和模棱兩可的(解釋和實現),並且語義版本明確地避免它們。因此,我認爲第二個功能應該始終是首選。
更新2:但第二個函數在「1.1」之前排序「1.2a」...我認爲沒有「一個適合所有」的功能...根據您的需要選擇「更合適」功能用例,或者更好,如果可以的話,按日期排序。
更新3:修改了第一個正確處理重要情況「1.2/1.10」的函數。作爲一個副作用,它打破了不太重要的情況「1.02/1.1」,顯然它現在是唯一的警告(也許它可以修復,但我不確定它是否值得)。因此,我現在推薦固定的第一個功能。
正則表達式會將「1.02」轉換爲「1」,所以'cmpVersion('1.01','1.02')'給出了錯誤的結果。 –
我用一種新方法編輯了這個答案的代碼,它修復了上述問題。評論將非常受歡迎,特別是要發現任何迴歸。順便說一句,這段代碼仍然不支持'cmpVersion('1.2alpha4','1.2alpha5')',但我想這會比較複雜。 –