eec icon indicating copy to clipboard operation
eec copied to clipboard

这种表格有办法处理吗,比如说多列合并的,一个sheet多个表格的

Open cnscottluo opened this issue 10 months ago • 5 comments

Image

场景一: 表头中的项目列,实际上内容区域是有3个单元格的,我用.asFullSheet().copyOnMerged() 读取出来的,就少了一些单元格的值

场景二: 一个sheet中,存在多个表格,怎么读取

测试表格.xlsx

cnscottluo avatar Apr 03 '25 07:04 cnscottluo

场景一:少了哪些单元格?我这边看是正常的

场景二:可以使用filter来过滤,比如你给出的两个表格中间有3个空行,就可以通过这3个空行来判断,也可以使用合计来判断是否到了表格末尾

wangguanquan avatar Apr 03 '25 08:04 wangguanquan

如果你提前知道每个Table的行数也可以使用filter来做

// Table1 过滤行号小于13的行
reader.sheet(0).asFullSheet().copyOnMerged().header(1).rows().filter(row -> row.getRowNum() <= 12).forEach(System.out::println);
// Table2 指定表头从16行开始
reader.sheet(0).asFullSheet().copyOnMerged().header(16).rows().forEach(System.out::println);

wangguanquan avatar Apr 03 '25 08:04 wangguanquan

场景一:少了哪些单元格?我这边看是正常的

这是我的代码:

@Test
    public void test5() {
        var path = "/Users/cnscottluo/Downloads/测试表格.xlsx";
        try (ExcelReader reader = ExcelReader.read(Paths.get(path))) {
            reader.sheet(0).asFullSheet().copyOnMerged().header(1).rows().map(Row::toMap).forEach(System.out::println);
        } catch (Exception ignored) {}
    }

结果如下:

{项目=型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号2, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号3, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号4, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号5, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号2, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号3, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号4, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号5, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=合计, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=项目, 1月=, 2月=, 3月=价格, 4月=数量, 5月=, 6月=null, 7月=null, 8月=null, 9月=null, 10月=null, 11月=null, 12月=null}
{项目=A类, 1月=A-1类, 2月=型号1, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号2, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号3, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号4, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号5, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号1, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号2, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号3, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号4, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号5, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=合计, 2月=合计, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=null, 1月=null, 2月=null, 3月=null, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}

但是其实想要的效果是,比如第一行的数据

{项目=A类&A-1类&型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}

因为 A类、A-1类、型号1 这三个单元格的值,才组成一个完整的项目

cnscottluo avatar Apr 14 '25 03:04 cnscottluo

如果你提前知道每个Table的行数也可以使用filter来做

// Table1 过滤行号小于13的行
reader.sheet(0).asFullSheet().copyOnMerged().header(1).rows().filter(row -> row.getRowNum() <= 12).forEach(System.out::println);
// Table2 指定表头从16行开始
reader.sheet(0).asFullSheet().copyOnMerged().header(16).rows().forEach(System.out::println);

你这种方式也行,但是具体看业务,有些情况下可能也不太行,因为甲方的表,真的是蛋疼的很(小学生水平做出来的表),可能你能确定的只有表头的内容,但是连表头的行数都没法确定,有可能这张表在第一行,另外一张表就有可能在第二行

cnscottluo avatar Apr 14 '25 03:04 cnscottluo

场景一:少了哪些单元格?我这边看是正常的

这是我的代码:

@Test public void test5() { var path = "/Users/cnscottluo/Downloads/测试表格.xlsx"; try (ExcelReader reader = ExcelReader.read(Paths.get(path))) { reader.sheet(0).asFullSheet().copyOnMerged().header(1).rows().map(Row::toMap).forEach(System.out::println); } catch (Exception ignored) {} } 结果如下:

{项目=型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号2, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号3, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号4, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号5, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号2, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号3, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号4, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=型号5, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=合计, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=项目, 1月=, 2月=, 3月=价格, 4月=数量, 5月=, 6月=null, 7月=null, 8月=null, 9月=null, 10月=null, 11月=null, 12月=null}
{项目=A类, 1月=A-1类, 2月=型号1, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号2, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号3, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号4, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=A-1类, 2月=型号5, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号1, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号2, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号3, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号4, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=B-1类, 2月=型号5, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=A类, 1月=合计, 2月=合计, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}
{项目=null, 1月=null, 2月=null, 3月=null, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}

但是其实想要的效果是,比如第一行的数据

{项目=A类&A-1类&型号1, 1月=, 2月=, 3月=, 4月=, 5月=, 6月=, 7月=, 8月=, 9月=, 10月=, 11月=, 12月=}

因为 A类、A-1类、型号1 这三个单元格的值,才组成一个完整的项目

copyOnMerged是作用是使合并区域数据一致,每个单元格都到取到相同的值,所以第一个单元格“项目”copyOnMerged之后的结果是"项目,项目,项目,1月,2月...",转为Map之后三个项目只会保留最后一个,类似的你可以不指定表头来转为Map,不指定表头时默认使用列号做为Key

reader.sheet(0).asFullSheet().copyOnMerged().rows().map(Row::toMap).forEach(System.out::println);

{0=项目, 1=项目, 2=项目, 3=1月, 4=2月, 5=3月}
{0=A类, 1=A-1类, 2=项目1, 3=null, 4=null, 5=null}
{0=A类, 1=A-1类, 2=项目2, 3=null, 4=null, 5=null}
{0=A类, 1=A-1类, 2=项目3, 3=null, 4=null, 5=null}
{0=A类, 1=A-1类, 2=项目4, 3=null, 4=null, 5=null}
{0=A类, 1=A-2类, 2=项目1, 3=null, 4=null, 5=null}
{0=A类, 1=A-2类, 2=项目2, 3=null, 4=null, 5=null}
{0=A类, 1=A-2类, 2=项目3, 3=null, 4=null, 5=null}
{0=A类, 1=A-2类, 2=项目4, 3=null, 4=null, 5=null}
{0=A类, 1=合计, 2=合计, 3=null, 4=null, 5=null}

至于“项目=A类&A-1类&型号1 ”这种效果则可以根据第一行相同的“项目”值来判断需要拼接哪些key

wangguanquan avatar Apr 15 '25 13:04 wangguanquan