Excel 使用 Java Apache POI 格式化

Excel formatting with Java Apache POI

我有一个 excel 文件,格式如下:

我想重组此格式并输出为以下格式:

这些部分是重复的,可以以任何顺序出现,但它们将采用任一格式。 'Check' 列有时跨行合并,如图所示。

我怎样才能做到这一点?

我使用Guava's Table作为数据结构来省去重新发明轮子

一些注意事项;

  • 矩阵或主元可能有一些数学技巧 表或函数式编程可以用很多东西做同样的工作 更少的代码。
  • 我不确定我是否为此使用了最新最好的 POI 类
  • 我已经尝试了蛮力和许多数据迭代,但希望它应该很容易理解。
  • 我假设您确定范围是可行的 定义数据的单元格数量(ABC、XYZ 等)
  • 我猜合并区域的第一行第一列总是 包含实际值(我不知道是否总是这样)
  • 可以使用 final 变量等轻松优化代码

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

public class ExcelFormatting {

    public static void main(String[] args) throws IOException {
        FileInputStream file = new FileInputStream(new File("Data.xls"));
        HSSFWorkbook workbook = new HSSFWorkbook(file);
        HSSFSheet sheet = workbook.getSheetAt(0);
        // ABC - Range A3:F7 in Data.xls
        Table<Integer, Integer, String> abc = getValues(sheet, 2, 0, 6, 5);
        //displayTable(abc);
        // XYZ - Range A11:E14 in Data.xls
        Table<Integer, Integer, String> xyz = getValues(sheet, 10, 0, 13, 4);
        //displayTable(xyz);

        Table<Integer, Integer, String> results = HashBasedTable.create();
        // Headers
        results.put(0, 0, "Name");
        results.put(0, 1, "Section");
        results.put(0, 2, "Check");
        results.put(0, 3, "Cat");
        results.put(0, 4, "Value");
        // Process ABC table
        results.putAll(transform(abc, "ABC", results.rowMap().size()));
        // Process XYZ table        
        results.putAll(transform(xyz, "XYZ", results.rowMap().size()));
        displayTable(results);
    }


    private static Table<Integer, Integer, String> transform(Table<Integer, Integer, String> table, String section, int offset) {
        Table<Integer, Integer, String> results = HashBasedTable.create();
        int maxRows = table.rowMap().size();
        int maxCols = table.columnMap().size();
        // First col is Name
        String name;
        // Second col is Check
        String check;
        String catA, catB, catC, catD = null;
        // offset is added so that table putAll doesn't overlap data rather than append it
        int outputRow = 0 + offset;
        for (int r = 0; r < maxRows; r++) {
            name = table.get(r, 0);
            check = table.get(r, 1);
            if (check == null) {
                check = "";
            }
            catA = table.get(r, 2);
            catB = table.get(r, 3);
            catC = table.get(r, 4);
            if (maxCols == 6) {
                catD = table.get(r, 5);
            }
            if (catA != null) {
                results = addRow(results, outputRow, name, section, check, "A", catA);
                outputRow++;
            }
            if (catB != null) {
                results = addRow(results, outputRow, name, section, check, "B", catB);
                outputRow++;
            }
            if (catC != null) {
                results = addRow(results, outputRow, name, section, check, "C", catC);
                outputRow++;
            }
            if (catD != null) {
                results = addRow(results, outputRow, name, section, check, "D", catD);
                outputRow++;
            }
        }
        return results;
    }

    private static Table<Integer, Integer, String> addRow(Table<Integer, Integer, String> table, int row, String name, String section, String check, String category, String value) {
        table.put(row, 0, name);
        table.put(row, 1, section);
        table.put(row, 2, check);
        table.put(row, 3, category);
        table.put(row, 4, value);
        return table;
    }

    // Convert "merged" data into normal populated cells
    private static Table<Integer, Integer, String> getValues(Sheet sheet, int minRow, int minCol, int maxRow, int maxCol) {
        Table<Integer, Integer, String> table = HashBasedTable.create();
        String result;
        Row row;
        Cell col;
        int r = minRow;
        int c;
        while (r <= maxRow) {
            row = sheet.getRow(r);
            c = minCol;
            while (c <= maxCol) {
                col = row.getCell(c);
                result = getValue(sheet, row, col);
                if (result != null) {
                    table.put(r - minRow, c - minCol, result);
                }
                c++;
            }
            r++;
        }
        return table;
    }

    private static String getValue(Sheet sheet, Row row, Cell cell) {
        String result = getCellValue(cell);
        if (result == null) {
            result = getMergedAreaValue(sheet, row.getRowNum(), cell.getColumnIndex());
        }
        return result;
    }

    private static String getCellValue(Cell cell) {
        String result = null;
        if (Cell.CELL_TYPE_STRING == cell.getCellType()) {
            result = cell.getStringCellValue();
        }
        if (Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {
            result = cell.getNumericCellValue() + "";
        }
        return result;
    }

    private static String getMergedAreaValue(Sheet sheet, int row, int col) {
        int mergedAreas = sheet.getNumMergedRegions();
        CellRangeAddress mergeArea;
        for (int i = 0; i < mergedAreas; i++) {
            mergeArea = sheet.getMergedRegion(i);
            if (mergeArea.isInRange(row, col)) {
                return getCellValue(
                        sheet.getRow(mergeArea.getFirstRow())
                        .getCell(mergeArea.getFirstColumn()));
            }
        }
        return null;
    }

    private static void displayTable(Table<Integer, Integer, String> table) {
        int maxRows = table.rowMap().size();
        int maxCols = table.columnMap().size();
        StringBuilder sb = new StringBuilder();
        String val;
        for (int r = 0; r < maxRows; r++) {
            for (int c = 0; c < maxCols; c++) {
                val = table.get(r, c);
                if (val != null) {
                    sb.append(val);
                }
                sb.append("\t\t");
            }
            sb.append('\n');
        }
        System.out.println(sb.toString());
    }


}

这应该会产生以下输出:

Name    Sect    Check   Cat     Value       
QQQ     ABC             A       1.0     
QQQ     ABC             D       5.0     
WWW     ABC     X       B       2.0     
WWW     ABC     X       D       5.0     
EEE     ABC     X       C       3.0     
EEE     ABC     X       C       4.0     
RRR     ABC             D       6.0     
QQQ     XYZ             A       1.0     
QQQ     XYZ             C       4.0     
WWW     XYZ     X       B       2.0     
WWW     XYZ     X       C       4.0     
WWW     XYZ     X       B       3.0     
WWW     XYZ     X       C       4.0     
EEE     XYZ     X       C       4.0 

您应该参考下面 link.It 包含可以使用 apache poi 完成的所有类型的事情 api.Its 的文档。

https://poi.apache.org/spreadsheet/quick-guide.html