| | |
| | | */ |
| | | function getIdFromColumnName(id, arr) { |
| | | try { |
| | | id = String(id).replace(/\$/g, ""); |
| | | // Get the letters |
| | | var t = /^[a-zA-Z]+/.exec(id); |
| | | if (t) { |
| | |
| | | */ |
| | | function getABCList(f) { |
| | | try { |
| | | if (typeof f !== "string") { |
| | | return []; |
| | | } |
| | | let regex = /[=\+\-\*\%\(\)\/\^\s]/g; |
| | | let fouList = ["SUM", "MAX", "MIN", "AVERAGE", "ABS"]; |
| | | let fouList = ["SUM", "MAX", "MIN", "AVERAGE", "ABS", "MEDIAN"]; |
| | | f = f |
| | | .replace(/\$/g, "") // 去掉 Excel 绝对引用符号,$D$14 视为 D14 |
| | | // 区间写法里的空格(AVERAGE( D14 : D15 ))会被下面的空白替换吃掉冒号, |
| | | // 导致区间被拆成两个独立单元格,先把区间规整成 D14:D15 |
| | | .replace(/\s*:\s*/g, ":") |
| | | .replace(regex, ",") |
| | | .replace(new RegExp('"&', "g"), "") |
| | | .replace(new RegExp('&"', "g"), ""); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 把单元格值转成可参与 eval 的字面量,空白单元格按 0 处理(与 Excel 一致) |
| | | * |
| | | * @param value 单元格的值 |
| | | * @returns 数值/原始值,空值返回 0 |
| | | */ |
| | | function toNumberLiteral(value) { |
| | | if (value === null || value === undefined) { |
| | | return 0; |
| | | } |
| | | if (typeof value === "string" && value.trim() === "") { |
| | | return 0; |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | /** |
| | | * 计算函数 |
| | | * |
| | | * @param f 字符串类型,表示待计算的公式 |
| | |
| | | */ |
| | | function compute(f, comValue) { |
| | | try { |
| | | let str = f; |
| | | if (typeof f !== "string") { |
| | | return undefined; |
| | | } |
| | | // 去掉 Excel 绝对引用符号,$D$14 与 D14 等价; |
| | | // 区间里的空格也要一并去掉,否则区间 token 会因空格匹配不上而展开失败 |
| | | let str = f.replace(/\$/g, "").replace(/\s*:\s*/g, ":"); |
| | | // 获取单元格对应值 |
| | | let arr = getAllCell(f); |
| | | let arr = getAllCell(str); |
| | | for (var a in comValue) { |
| | | if ( |
| | | comValue[a] !== "undefined" && |
| | |
| | | } |
| | | } |
| | | } |
| | | // 解析公式参数,特别是带:的 |
| | | let arr0 = getABCList(f); |
| | | let obj = {}; |
| | | arr0.forEach((item) => { |
| | | if (item.includes(":")) { |
| | | let arr1 = []; |
| | | let r0 = getIdFromColumnName(item.split(":")[0]).r; |
| | | let c0 = getIdFromColumnName(item.split(":")[0]).c; |
| | | let r1 = getIdFromColumnName(item.split(":")[1]).r; |
| | | let c1 = getIdFromColumnName(item.split(":")[1]).c; |
| | | for (let i = Number(r0); i <= Number(r1); i++) { |
| | | for (let u = Number(c0); u <= Number(c1); u++) { |
| | | arr1.push({ |
| | | r: i, |
| | | c: u, |
| | | }); |
| | | } |
| | | } |
| | | let arr2 = []; |
| | | arr1.forEach((m) => { |
| | | arr2.push(getColumnNameFromId(`${m.c}` + "-" + `${m.r}`)); |
| | | }); |
| | | obj[item.split(":").join("-")] = arr2.join(","); |
| | | } else { |
| | | obj[item] = item; |
| | | // 把区间参数(如 SUM(D14:D15) 中的 D14:D15)展开成单元格列表 D14,D15 |
| | | getABCList(str).forEach((token) => { |
| | | if (!token.includes(":")) { |
| | | return; |
| | | } |
| | | const parts = token.split(":"); |
| | | const start = getIdFromColumnName(parts[0]); |
| | | const end = getIdFromColumnName(parts[1]); |
| | | const cells = []; |
| | | for (let i = Number(start.r); i <= Number(end.r); i++) { |
| | | for (let u = Number(start.c); u <= Number(end.c); u++) { |
| | | cells.push(getColumnNameFromId(`${u}` + "-" + `${i}`)); |
| | | } |
| | | } |
| | | str = str.replace(token, cells.join(",")); |
| | | }); |
| | | str = str.replace(new RegExp(":", "g"), ""); |
| | | // 替换参数 |
| | | for (var a in obj) { |
| | | str = str.replace(new RegExp(a, "g"), obj[a]); |
| | | // 计算:一次性替换所有参数,避免 D1 与 D14 这类前缀互相污染 |
| | | const keys = Object.keys(arr); |
| | | if (keys.length > 0) { |
| | | const pattern = new RegExp( |
| | | keys |
| | | .sort((x, y) => y.length - x.length) |
| | | .map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) |
| | | .join("|"), |
| | | "g" |
| | | ); |
| | | str = str.replace(pattern, (m) => String(toNumberLiteral(arr[m]))); |
| | | } |
| | | // 计算 |
| | | for (var a in arr) { |
| | | str = str.replace(new RegExp(a, "g"), arr[a]); |
| | | const result = eval(str); |
| | | // 除零等非有限结果不写回单元格 |
| | | if (typeof result === "number" && !isFinite(result)) { |
| | | return undefined; |
| | | } |
| | | return eval(str); |
| | | return result; |
| | | } catch (error) {} |
| | | } |
| | | |