說明
本文實現了一個從阿拉伯數字到中文數字,以及從中文數字到阿拉伯數字的轉換演算法。
同時用Vuejs和Angularjs同時實現了一遍,對比了一下這兩個框架的優劣。在本例中,Vuejs的方便靈活性完勝Angularjs。
原始碼在這裡
阿拉伯數字轉中文
給定一個阿拉伯數字,把它轉變為漢語表示的數字。
演算法
根據中文的計數方法,可以把阿拉伯數字按4個一組分成若干section,每個section從低到高的單位分別為 “”,“萬”,“億”,“萬億”。
每個section內的轉換方法是一樣的,比如1234,就是”一千二百三十四”,加上對應的單位,如“萬”,就是“一千二百三十四萬”。但是在其中又有些細節需要注意:
-
結尾的零都忽略,如1200,就是一千二百
-
中間的零,只需要用一個零表示,如1004,是一千零四
-
如果整個section都是0,全部忽略
-
如果section在10到19之間,則十位可以省略一;否則,十位上的“一”都不能省。如12就是“十二”,312就是“三百一十二”
中文轉阿拉伯數字
給定一箇中文數字,如“一千二百三十四萬”,把它們轉換成阿拉伯數字
演算法
跟上面類似,以“萬”,“億”,“萬億”為分割位,先把中文分成若干section,每個section的轉換方法一樣,然後section數值乘以相應的權重,如section為“萬”就是乘以10000,“億”是乘以100000000,最低位的section,權重就是1。
將每個section的結果累加就是最終結果。
每個section最多8個漢字,都是以“數字+單位”的形式成對出現。將數字*單位
的結果累加起來就是最終結果。單位從低到高就是1,10, 100, 1000。
需要注意的細節有:
-
“零”忽略即可
-
如果第一位是“十”,則數字預設為一。
實現細節
分別通過Vuejs和angularjs實現了一遍,正好可以對比一下二者的不同。大部分程式碼二者都差不多。
但是為了方便閱讀,我對阿拉伯數字採用了千分位分隔,當使用者在輸入框中輸入完成按下回車後,輸入框內的阿拉伯數字自動用逗號分隔。差異注意出現在這個實現方法上。
Vuejs實現
// html檢視:
<input type="text" v-model="ArabNum|thousandth">
// js邏輯:
var app = new Vue({
el: "#app",
data: {
ArabNum: 0,
ChineseNum: "",
//ChineseSymbole: ["零", "壹", "貳", "叄", "肆", "伍", "陸", "柒", "捌", "玖"],
ChineseSymbole: ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"],
ChineseSection: ["", "萬", "億", "萬億"],
//ChineseUnit: ["", "拾", "佰", "仟"],
ChineseUnit: ["", "十", "百", "千"],
ChineseUnitArab: {
"零": 0,
"一": 1,
"二": 2,
"三": 3,
"四": 4,
"五": 5,
"六": 6,
"七": 7,
"八": 8,
"九": 9,
"十": 10,
"百": 100,
"千": 1000,
"萬": 10000,
"億": 100000000,
"萬億": 1000000000000,
}
},
// 區別主要在這裡:
filters: {
thousandth: {
read: function(v) {
var str = "";
while (v > 0) {
var left = "" + (v % 1000);
v = Math.floor(v / 1000);
if (v > 0) {
while (left.length < 3) {
left = "0" + left;
}
}
if (str == "") {
str = left;
} else {
str = left + "," + str;
}
}
return str;
},
write: function(v) {
return parseInt(v.replace(/,/g, ""));
},
},
},
methods: {
Arab2Chn: function(v) { ... },
Arab2Chn_section: function(v) { ... },
Chinese2Arab: function(str) { ... },
Chinese2Arab_section: function(str) { ... },
},
computed: { ... },
})
Vuejs方便的地方在於,filter可以用在v-model中,只要分別設計read和write函式即可實現雙向繫結。read用於model到view的轉換,write用於view到model的轉換。
Angularjs實現
相比於Vuejs,如果在ng-model中直接使用filter,會報錯:
<input type="text" ng-model="ArabNum|thousandth" >
// error:
Expression `ArabNum|thousandth` is non-assignable
為了實現和Vuejs類似的邏輯,我首先google了一下,發現只能通過directive實現:
app.directive("thousandth", function() {
return {
require: "ngModel",
link: function(scope, elm, attr, ngModel) {
function thousandth(v) {
var str = "",
v = "" + v;
v = v.replace(/,/g, "");
while (v > 0) {
var left = "" + (v % 1000);
v = Math.floor(v / 1000);
if (v > 0) {
while (left.length < 3) {
left = "0" + left;
}
}
if (str == "") {
str = left;
} else {
str = left + "," + str;
}
}
return str;
}
elm.on("blur", function(v) {
elm.val(thousandth(ngModel.$modelValue));
});
// model -> view
ngModel.$formatters.push(function(data) {
return thousandth(data)
})
// view -> model
ngModel.$parsers.push(function(v) {
v = "" + v;
return parseInt(v.replace(/,/g, ""));
});
}
}
})
可以看到,首先ng的語法要麻煩很多。而且$formatters
只有在內部的model被改變時,才會對view生效。比如input改變時,$parsers
先呼叫(V–>M),返回值直接給了ngModel,但是$formatters
不會呼叫,即M–>V不會被呼叫,否則 M修改V,V又修改M,就是死迴圈了。
只有你通過程式修改了ArabNum
後,$formatters
才會呼叫(M–>V)。所以,必須通過jquery的方式,在blur函式中,對element的value進行直接修改,才能實現上述Vue的效果。
總結
只要仔細一點,耐心一點,兩個數字表示方式的轉換還是比較容易實現的。
通過對比Vue和angular可以看到,Vue確實比Ng要方便些。這只是其中的一個方面。