EPPlus 问题 FormulaR1C1 已损坏 Excel 已生成

EPPlus issue FormulaR1C1 corrupted Excel generated

我正在用一组数据生成一个 excel sheet,其中包括必须应用于列的公式。

例如:

C2= (B2-A2)/A2, C3= (B3-A3)/A3, C101 = (B101-A101)/A101

这些公式工作正常,当我引用列 R (id= 18) 时,excel 正确生成,没有任何错误,但是当 excel 更改为列时会损坏 excel ID = 399。

这是我的 xml 代码和数据。这里 ColumnId 表示哪一列,FieldCode 表示列主题,FieldCalculation 表示该列的公式。

  <Header>
    <RowId>1</RowId>
    <HeaderCells>
      <HeaderCell>
        <ColumnId>2</ColumnId>
        <FieldCode>ST1001</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>1</ColumnId>
        <FieldCode>ST1000</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>3</ColumnId>
        <FieldCode>ST1002</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>4</ColumnId>
        <FieldCode>ST1003</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>5</ColumnId>
        <FieldCode>ST1004</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>6</ColumnId>
        <FieldCode>ST1005</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>7</ColumnId>
        <FieldCode>ST1006</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>8</ColumnId>
        <FieldCode>ST1007</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>9</ColumnId>
        <FieldCode>ST1008</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>10</ColumnId>
        <FieldCode>ST1009</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>11</ColumnId>
        <FieldCode>ST1010</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>12</ColumnId>
        <FieldCode>ST1011</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>13</ColumnId>
        <FieldCode>ST1012</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>14</ColumnId>
        <FieldCode>ST1013</FieldCode>
        <FieldCalculation>UPPER(TRIM(CONCATENATE('ST1004', 'ST1005', 'ST1006', 'ST1007, 'ST1008', 'ST1009', 'ST1010', 'ST1011', 'ST1012')))</FieldCalculation>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>15</ColumnId>
        <FieldCode>ST1030</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>400</ColumnId>
        <FieldCode>ST1041</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>401</ColumnId>
        <FieldCode>ST1043</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>399</ColumnId>
        <FieldCode>ST1045</FieldCode>
        <FieldCalculation>(ST1043-ST1041)/ST1041</FieldCalculation>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>19</ColumnId>
        <FieldCode>ST1073</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>20</ColumnId>
        <FieldCode>ST1074</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>21</ColumnId>
        <FieldCode>ST1075</FieldCode>
      </HeaderCell>
      <HeaderCell>
        <ColumnId>22</ColumnId>
        <FieldCode>ST1076</FieldCode>
        <FieldCalculation>ST1073+ST1074+ST1075</FieldCalculation>
      </HeaderCell>
    </HeaderCells>
  </Header>

这是将字段计算转换为公式 1c1 的代码,用列的绝对位置替换 header 主题。

例如:

1) UPPER(TRIM(CONCATENATE('ST1004', 'ST1005', 'ST1006', 'ST1007, 'ST1008', 'ST1009', 'ST1010', 'ST1011', 'ST1012')))转换为UPPER(TRIM(CONCATENATE(RC[-9],RC[-8],RC[-7],RC[-6],RC[-5],RC[-4],RC[-3],RC[-2],RC[-1])))

2) (ST1043-ST1041)/ST1041转换为(RC[2]-RC[1])/RC[1]

3) ST1073+ST1074+ST1075转换为RC[-3]+RC[-2]+RC[-1]

代码:

    /// <summary>
    /// Get the formula for the field
    /// </summary>
    /// <param name="formulaString">The formula string with header topics</param>
    /// <param name="headercells">The header cells list in the excel</param>
    /// <param name="columnId">The current column id</param>
    /// <returns></returns>
    public static string GetFieldFormula(string fieldCalculation, List<HeaderCell> headercells, int columnId)
    {
        string[] multiArray = fieldCalculation.Split(new Char[]
        { '!', '@', '#', '$', '%', '^', '&', '*', '(', ')','-', '_', '=', '+', '{', '}', '[', ']', ';', ':', '"', '<', '>', '?', ',', '.', '/', '~', '`', '\',  '|'});
        foreach (string column in multiArray)
        {
            string columnname = column.Replace("'", "").Trim();
            int? machingcellId = headercells.Find(headcell => headcell.FieldCode == columnname)?.ColumnId;
            if (machingcellId > 0)
            {
                string matchingcellname = "RC[" + (machingcellId - columnId) + "]";
                fieldCalculation= Regex.Replace(fieldCalculation, column, matchingcellname);
            }
        }
        return fieldCalculation;
    }

然后将此字段公式应用到整个列,如下所示。

这里i是当前列id,headerCellsobject包含反序列化的xml数据。

    fieldCalculation = if (!string.IsNullOrWhiteSpace(fieldCalculation))
    {
        string formulaString = null;
        formulaString = GetFieldFormula(fieldCalculation, headerCells, i); 
        sheet.Cells[2, i, rowcount - 2, i].FormulaR1C1 = formulaString;                    
    }

In this example when I change ST1045 (id =399) column's id to 18, the excel is not corrupted. If I apply only one formula at a time out of these three formula, then also the excel is not corrupted. I cant find what is the exact reason for this issue. I have used the latest version of EPPlus 4.5.3.1. Please give your suggestions.  

我可以通过更改 excel 版本或限制应用公式的行数来解决此问题。

ASFAIU 此问题是由于打开从 EPPlus 库创建的 excel 文件时消耗的内存所致。

我最初使用的是 excel 2007,当我更改为 excel 2016 时,文件没有损坏。

由于我正在构建的应用程序应支持 excel 2010,因此我限制了应用公式的行数。如果不是,则公式将应用于列中的所有行。然后问题也解决了。

我用这个:

ws.Cells[row,column+1].Formula = Regex.Replace(ws.Cells[row,column].Formula, @"[A-Z]+(?=\d)+", ExcelCellAddress.GetColumnLetter(column+1));

通过正则表达式更改列的字母,这会验证在公式中搜索单元格的字母和数字 [A-Z]+(?=\d)+;