前言
在我們使用Excel時,經常會遇到一個問題,就是導入Excel時公式顯示爲【#Ref!】的情況。這通常是因爲公式中引用的單元格已被刪除或對應的工作表被刪除,導致原公式無法識別對應的參數而顯示爲【#Ref!】。
比如在一張Excel表中,sheet1 中 A1 單元格的公式爲‘=Sheet2!B1’,如果 Sheet2 由於各種歷史原因丟失,那麼此時 sheet1 中 A1 計算結果爲【#Ref!】,如果此時想查找到 Sheet2 怎麼辦呢?今天小編就將爲大家介紹如何用葡萄城公司的Java API 組件——GrapeCity Documents for Excel(以下簡稱GcExcel)來查找丟失的Sheet頁。
具體操作步驟
1)準備
首先創建公式
Workbook workbook = new Workbook();
IWorksheet workSheet = workbook.getWorksheets().get(0);
workSheet.setName("sheet1");
workSheet.getRange(1, 1).setFormula("sheet2!F7");
workSheet.getRange(3, 3).setFormula("Sheet3!A1");
2)查找
接下來,通過Find進行遍歷查詢所有的【#Ref!】公式,GcExcel提供了各種類型的查找替換。
FindOptions tempVar = new FindOptions();
//設置通過文本查找
tempVar.setLookIn(FindLookIn.Texts);
IRange range = null;
do {
range = searchRange.find("Ref", range, tempVar);
if (range == null) {
break;
} else {
//在這裏做相應的邏輯
}
} while (true);
上述代碼是查找替換的基礎代碼,我們發現上述代碼 searchRange 未定義,searchRange 可以是整個 sheet, 也可以是一片區域,接下來我們定義searchRange 。
3)特殊單元格
GcExcel 提供了找到錯誤公式的能力,通過 specialCells 可以查找到錯誤公式,並返回錯誤公式的區域爲第二步中的searchRange變量 。
IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors);
現在我們已經找到了對應的所有爲【#Ref!】的單元格,接下來開始做查找成功之後的邏輯。
4)公式解析
查找成功後,可以通過 range.getFormula() 獲取到公式,接下來對公式進行解析,由於 Excel 公式有的簡單,有的複雜,不能單純判斷等號後,感嘆號前的字符串爲sheet 名稱,我們要通過公式樹去遍歷解析。
GcExcel 提供了公式解析器,調用 parse 拿到公式樹,之後可以通過 getWorksheetName 獲取 sheetName,相關代碼如下:
//將公式中等號去掉,並進行解析
FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", ""));
addNotFoundSheet(syntaxTree.getRoot(), workbook);
addNotFoundSheet 定義如下:
private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) {
if (node == null) {
return;
}
if (node instanceof ReferenceNode) {
String sheetName = ((ReferenceNode) node).getReference().getWorksheetName();
if (workbook.getWorksheets().get(sheetName) == null) {
IWorksheet tempSheet = workbook.getWorksheets().add();
tempSheet.setName(sheetName);
}
}
for (SyntaxNode child : node.getChildren()) {
addNotFoundSheet(child, workbook);
}
}
在上述代碼中首先判斷node是否是 ReferenceNode 類型,如果是的話,通過 node.getReference().getWorksheetName() 獲取 sheetName,並判斷當前工作簿是否存在此sheet,如果不存在則進行添加。
處理後,對其子節點進行遞歸判斷,重複上述步驟,直到 node 節點爲 null,退出遞歸查詢。
最後附上完整版的代碼:
public static void main(String[] args) throws Exception {
Workbook workbook = new Workbook();
IWorksheet workSheet = workbook.getWorksheets().get(0);
workSheet.setName("sheet1");
workSheet.getRange(1, 1).setFormula("sheet2!F7");
workSheet.getRange(3, 3).setFormula("Sheet3!A1");
FindOptions tempVar = new FindOptions();
tempVar.setLookIn(FindLookIn.Texts);
IRange searchRange = workSheet.getCells().specialCells(SpecialCellType.Formulas, SpecialCellsValue.Errors);
IRange range = null;
do {
range = searchRange.find("Ref", range, tempVar);
if (range == null) {
break;
} else {
FormulaSyntaxTree syntaxTree = FormulaSyntaxTree.Parse(range.getFormula().replaceFirst("=", ""));
addNotFoundSheet(syntaxTree.getRoot(), workbook);
}
} while (true);
}
private static void addNotFoundSheet(SyntaxNode node, Workbook workbook) {
if (node == null) {
return;
}
if (node instanceof ReferenceNode) {
String sheetName = ((ReferenceNode) node).getReference().getWorksheetName();
if (workbook.getWorksheets().get(sheetName) == null) {
IWorksheet tempSheet = workbook.getWorksheets().add();
tempSheet.setName(sheetName);
}
}
for (SyntaxNode child : node.getChildren()) {
addNotFoundSheet(child, workbook);
}
}
通過上述代碼,可以查找到”sheet2“與”sheet3“,並進行添加。
總結
以上就是使用GcExcel解決導入Excel文件的時候公式爲【#Ref!】問題的全過程,如果您想了解更多詳細信息,歡迎點擊這裏查看。