找回密码
 立即注册

QQ登录

只需一步,快速开始

Ellia.Duan SpreadJS 开发认证
超级版主   /  发表于:2024-1-26 17:49  /   查看:499  /  回复:0
本帖最后由 JoeJin 于 2024-1-26 18:06 编辑

在 GcExcel 中,导入 Excel 文件或者 json 文件,进行公式计算时,发现一部分公式计算结果为”#Ref!“ ,

这个公式计算结果的解释与 Excel 是保持一致的,如 sheet1 中 A1 单元格的公式为‘=Sheet2!B1’,如果 Sheet2 由于各种历史原因丢失,那么此时 sheet1 中 A1 计算结果为‘#Ref!’,如果此时想查找到 Sheet2 怎么办呢?
GcExcel 提供了查找不存在引用 sheet 的能力
一、准备
首先,我们先创建公式
  1. Workbook workbook = new Workbook();
  2. IWorksheet workSheet = workbook.getWorksheets().get(0);
  3. workSheet.setName("sheet1");
  4. workSheet.getRange(1, 1).setFormula("sheet2!F7");
  5. workSheet.getRange(3, 3).setFormula("Sheet3!A1");
复制代码
二、查找
接下来,我们通过Find进行遍历 查询,关于Find可以查看此篇文章,GcExcel提供了各种类型的查找替换
https://demo.grapecity.com.cn/do ... emos/findandreplace
  1. FindOptions tempVar = new FindOptions();
  2. tempVar.setLookIn(FindLookIn.Texts);
  3. IRange range = null;
  4. do {
  5. range = searchRange.find("Ref", range, tempVar);
  6. if (range == null) {
  7. break;
  8. } else {
  9. //在这里做相应的逻辑
  10. }
  11. } while (true);
复制代码

上述代码是查找替换的基础代码,我们发现上述代码 searchRange 未定义,
searchRange 可以是整个 sheet, 可以是一片区域,这里我们搞点不一样的东西。
三、特殊单元格
GcExcel 提供了找到错误公式的能力,通过 specialCells 可以查找到错误公式,并返回错误公式的区域。
关于 specialCells,可以查看此文章
https://demo.grapecity.com.cn/do ... /demos/specialcells
  1. IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors);
复制代码


目前为止,已经获取了查找区域,以及根据值"Ref"进行查找,接下来做查找成功的事情了。
四、公式解析
查找成功后,可以通过 range.getFormula() 获取到公式,接下来对公式进行解析,由于 Excel 公式有的简单,有的复杂,不能单纯判断等号后,感叹号前的字符串为sheet 名称,我们要通过公式树去遍历解析。
GcExcel 提供了公式解析器,可以参考此篇文章,调用 parse 拿到公式树,
https://www.grapecity.com.cn/dev ... t-doc-content_title
之后可以通过 getWorksheetName 获取 sheetName,相关代码如下:
  1. FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", ""));
  2. addNotFoundSheet(syntaxTree.getRoot(), workbook);
复制代码

其中 addNotFoundSheet 方法定义如下:
  1. private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) {
  2.         if (node == null) {
  3.             return;
  4.         }
  5.         if (node instanceof ReferenceNode) {
  6.             String sheetName = ((ReferenceNode) node).getReference().getWorksheetName();
  7.             if (workbook.getWorksheets().get(sheetName) == null) {
  8.                 IWorksheet tempSheet = workbook.getWorksheets().add();
  9.                 tempSheet.setName(sheetName);
  10.             }
  11.         }
  12.         for (SyntaxNode child : node.getChildren()) {
  13.             addNotFoundSheet(child, workbook);
  14.         }
  15.     }
复制代码

在上述代码中首先判断node是否是 ReferenceNode 类型,如果是的话,通过 node.getReference().getWorksheetName() 获取 sheet 名称。然后在工作簿中进行里添加。
处理后,对其子阶段进行递归判断,重复上述步骤,直到 node 节点为 null,退出递归查询。

完整代码如下:
  1. public static void main(String[] args) throws Exception {
  2.         Workbook workbook = new Workbook();
  3.         IWorksheet workSheet = workbook.getWorksheets().get(0);
  4.         workSheet.setName("sheet1");
  5.         workSheet.getRange(1, 1).setFormula("sheet2!F7");
  6.         workSheet.getRange(3, 3).setFormula("Sheet3!A1");


  7.         FindOptions tempVar = new FindOptions();
  8.         tempVar.setLookIn(FindLookIn.Texts);
  9.         IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors);

  10.         IRange range = null;
  11.         do {
  12.             range = searchRange.find("Ref", range, tempVar);
  13.             if (range == null) {
  14.                 break;
  15.             } else {
  16.                 FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", ""));
  17.                 addNotFoundSheet(syntaxTree.getRoot(), workbook);
  18.             }
  19.         } while (true);

  20.     }

  21.     private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) {
  22.         if (node == null) {
  23.             return;
  24.         }
  25.         if (node instanceof ReferenceNode) {
  26.             String sheetName = ((ReferenceNode) node).getReference().getWorksheetName();
  27.             if (workbook.getWorksheets().get(sheetName) == null) {
  28.                 IWorksheet tempSheet = workbook.getWorksheets().add();
  29.                 tempSheet.setName(sheetName);
  30.             }
  31.         }
  32.         for (SyntaxNode child : node.getChildren()) {
  33.             addNotFoundSheet(child, workbook);
  34.         }
  35.     }
复制代码








0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部