Browse Source

用户公式解析。

Chenshilong 8 years ago
parent
commit
323ee91f6f
2 changed files with 141 additions and 3 deletions
  1. 128 3
      public/calc_util.js
  2. 13 0
      test/calculation/test_analyzer.js

+ 128 - 3
public/calc_util.js

@@ -1,7 +1,7 @@
 /**
  * Created by Tony on 2017/6/21.
- * Modified by CSL, 2017-08-01
- * 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等
+ * Modified by CSL, 2017-08-01 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等。
+ * added by CSL, 2017-09-01 增加公式解析对象analyzer,用于解析用户修改公式、自定义表达式
  */
 
 let executeObj = {
@@ -39,6 +39,129 @@ let executeObj = {
     }
 };
 
+let analyzer = {
+    standard: function(expr){
+        let str = expr;
+        str = str.replace(/\s/g, "");               // 去空格、去中文空格
+        str = str.replace(/(/g, "(");              // 中文括号"("换成英文括号"("
+        str = str.replace(/)/g, ")");              // 中文括号")"换成英文括号")"
+        str = str.replace(/f/g, "F");               // f换成F
+        console.log(str);
+        return str;
+    },
+
+    analyzeCalcBase: function(expr){
+        // 前提:必须无空格、无特殊符号
+        function getCalcBase(expr){
+            let base = '',
+                iPos1 = -1, iPos2 = -1;
+            for (let i = 0; i < expr.length; i++) {
+                if (expr[i] === '['){
+                    iPos1 = i;
+                }
+                else if (iPos1 != -1 && expr[i]===']'){
+                    iPos2 = i;
+                };
+
+                if (iPos1 != -1 && iPos2 != -1){
+                    base = expr.slice(iPos1, iPos2 + 1);
+                    break;
+                }
+            };
+            return base;
+        };
+        function calcBaseToIDExpr(base){
+            // for test.
+            let id = -1;
+            if (base == '[人工费]'){
+                id = 111;
+            }
+            else if (base == '[材料费]'){
+                id = 222;
+            }
+            else if (base == '[机械费]'){
+                id = 333;
+            }
+            else id = 999;
+
+            return "@('" + id + "')";
+        };
+
+        while (expr.indexOf('[') > 0) {
+            let base = getCalcBase(expr);
+            let id = calcBaseToIDExpr(base);
+            let baseValue = base.slice(1, -1);   // []会给下面的正则带来干扰,这里去掉
+            var pattBase =new RegExp(baseValue, "g");
+            expr = expr.replace(pattBase, id);
+            expr = expr.replace(/\[@\('/g, "@('");      // [@('
+            expr = expr.replace(/'\)\]/g, "')");        // ')]
+        };
+
+        return expr;
+    },
+
+    analyzeLineRef: function(expr){
+        function isOperator(char){
+            var operator = "+-*/()";
+            return operator.indexOf(char) > -1;
+        };
+        function codeToID(code){
+            return eval(parseFloat(code)+1);
+        };
+        // 前提:必须无空格、无特殊符号、标准大写F
+        function getSection(expr){
+            let section = '',
+                iPos1 = -1, iPos2 = -1;
+            for (let i = 0; i < expr.length; i++) {
+                if (expr[i] === 'F'){
+                    iPos1 = i;
+                }
+                else if (iPos1 != -1 && isOperator(expr[i])){
+                    iPos2 = i;
+                }
+                else if (iPos1 != -1 && i == expr.length - 1){
+                    iPos2 = i + 1;
+
+                };
+                if (iPos1 != -1 && iPos2 != -1){
+                    section = expr.slice(iPos1, iPos2);
+                    break;
+                }
+            };
+            return section;
+        };
+        function sectionToIDExpr(section){
+            if (section){
+                let code = section.slice(1);
+                if (isNaN(code)){
+                    return '错误'      // 这里的返回提示不能加上section,因为会无限循环
+                }
+                else
+                    return "@('" + codeToID(code) + "')";
+            }
+            else return '';
+        };
+
+        while (expr.indexOf('F') > 0) {
+            let sec = getSection(expr);
+            let id = sectionToIDExpr(sec);
+            var pattSec =new RegExp(sec, "g");
+            expr = expr.replace(pattSec, id);
+        };
+        return expr;
+    },
+
+    analyzeUserExpr: function(expr){
+        // 标准化:处理特殊字符、中文符号、大小写
+        expr = this.standard(expr);
+        // 先换掉计算基数
+        expr = this.analyzeCalcBase(expr);
+        // 再换掉行引用
+        expr = this.analyzeLineRef(expr);
+        return expr;
+    }
+};
+
 class Calculation {
     // 先编译公用的基础数据
     compilePublics(feeRates, labourCoes, feeTypes, calcBases){
@@ -234,4 +357,6 @@ class Calculation {
             }
         }
     }
-}
+};
+
+export default analyzer;

+ 13 - 0
test/calculation/test_analyzer.js

@@ -0,0 +1,13 @@
+/**
+ * Created by CSL on 2017-09-01.
+ */
+var test = require('tape');
+import analyzer from '../../public/calc_util';
+
+test('解析测试', function(t){
+    let userExpr = "12 +[人工费]*1.2+f4+ (F6+ f10) +F23+[人工费] + f6+[材料费]";
+    let rst = analyzer.analyzeUserExpr(userExpr);
+    console.log(rst);
+    t.equal(rst, "12+@('111')*1.2+@('5')+(@('7')+@('11'))+@('24')+@('111')+@('7')+@('222')");
+    t.end();
+});