liding
9 小时以前 e3a05337b453b5f09e977f4196930e8c245fb139
src/utils/excelFountion.js
@@ -169,6 +169,7 @@
 */
function getIdFromColumnName(id, arr) {
  try {
    id = String(id).replace(/\$/g, "");
    // Get the letters
    var t = /^[a-zA-Z]+/.exec(id);
    if (t) {
@@ -245,9 +246,16 @@
 */
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"), "");
@@ -280,6 +288,22 @@
}
/**
 * 把单元格值转成可参与 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 字符串类型,表示待计算的公式
@@ -288,9 +312,14 @@
 */
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" &&
@@ -310,43 +339,40 @@
        }
      }
    }
    // 解析公式参数,特别是带:的
    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) {}
}