【Apache POI】判断非空单元格
首先
使用Apache POI库读取Excel时,我想跳过具有删除线或隐藏的单元格,并查找了解了一种方法。下面是我作为个人备忘录记录下来的内容,如果觉得有帮助就请参考。
※基本的Apache POI写法将被省略。
目录
-
- 不显示的行
-
- 判断不显示的行
-
- 判断不显示的列
取消线
整个单元格有取消线
单元格内的部分有取消线
1. 不展示身份证明

1. 判断非表示行
我将进行判断,看这一行是否被隐藏起来了。
for(Row row : sheet){
// 行が非表示か判定
if(row.getZeroHeight()){
// 非表示の場合、次の行を読み込む
continue;
}
...
}
2. 判断隐藏列
我们要判断列是否被隐藏。
在Apache POI中,我们是按照工作簿➡️工作表➡️行➡️列的顺序进行读取的,
因此针对列,我们需要以单元格为单位进行判断。
另外,由于单元格类中没有隐藏判断,因此需要在工作表类中编写判断处理。
for(Cell cell : row){
// 列が非表示か判定
if(sheet.isColumnHidden(cell.getColumnIndex())){
// 非表示の場合、次のセルを読み込む
continue;
}
...
}
※这个处理在每个单元格中都要进行判断,但是如果读取大量的数据文件或多个文件一次性加载时,处理会变得非常慢。如果要处理大量的数据,可以将列号保持在列表中会更好。
取消线 – qǔ xīàn

1. 整格中的格子有一条删除线。
这是判断单元格是否有删除线的方法。
for(Cell cell : row){
// セルのフォントを取得
CellStyle style = c.getCellStyle();
Font font = c.getSheet().getWorkbook().getFontAt(style.getFontIndex());
// セルに取消線があるかどうかを判定
if(font.getStrikeout()){
// 取消線がある場合、次のセルを読み込む
continue;
}
...
}
2. 细胞内部有一部分有删除线。
如果单元格的一部分有删除线,则需要根据读取的Excel文件扩展名的类型来选择使用的写法。
※有关HSSF和XSSF的详细信息,请参阅此处。
如果文件的扩展名是xlsx的话
获取已划掉的字符串。
例)あいうえお → うえ
// XSSFRichTextString形式にてセルの値を取得
XSSFRichTextString richStr = (XSSFRichTextString) cell.getRichStringCellValue();
// セル内の文字列に当たっているフォントの塊の数を取得
int cnt = richStr.numFormattingRuns();
// フォントが当たっていないときは0になる
if (cnt == 0 ) {
continue;
}
for (int i = 0; i < cnt; i++;) {
// インデックスがi番目のフォントの塊を取得
XSSFFont xssfFont = richStr.getFontOfFormattingRun(i);
// 塊にフォントが当たっていなかった場合
if (xssfFont == null) {
continue;
}
// 塊にフォントが当たっていた場合、取消線があるかどうかの判定
if (xssfFont.getStrikeout()) {
// 取り消し線がある場合、i番目のインデックスの塊の文字列を取得
System.out.println(richStr.getCTRst().getRArray(i).getT());
}
}
上述的情况下,对于xlsx文件,可以相对简单地获取。我自己对于FormattingRun系列的处理意义有些困惑,但根据处理的结果看,似乎是将“あいうえお”按照“あい”、“うえ”和“お”的块进行分割(只是“あい”没有字体,“うえ”和“お”的获取涉及到文字大小、字体(如メイリオ)以及是否有删除线等)。
如果文件的扩展名是xls(Excel 97-2003版本)。
由于HSSFFont的类型较旧的版本,可能无法像XSSF那样直接获取字体本身,而只能获取带有删除线属性的索引。
String cellStr = cell.getStringCellValue();
HSSFRichTextString richStr = (HSSFRichTextString)cell.getRichStringCellValue();
// フォントが当たっている塊の数を取得
int cnt = richStr.numFormattingRuns();
if (cnt == 0){
continue;
} else {
int startStrikeoutIndex = -1;
boolean isStrikeoutStartIndex = false;
for (int i = 0; i < cnt; i++;) {
// インデックスがi番目のフォントの塊を取得
Font hssfFont = wb.getFontAt(richStr.getFontOfFormattingRun(i));
int index = richStr.getIndexOfFormattingRun(i);
// 塊にフォントが当たっていなかった場合
if (hssfFont == null) {
if (isStrikeoutStartIndex) {
System.out.println(cellStr.substring(startStrikeoutIndex, index));
isStrikeoutStartIndex = false;
}
continue;
}
// フォント設定はあるが取り消し線がない場合
if (!hssfFont.getStrikeout()) {
if (isStrikeoutStartIndex) {
System.out.println(cellStr.substring(startStrikeoutIndex, index));
isStrikeoutStartIndex = false;
}
}
// 一部に取り消し線がある場合
else if (hssfFont.getStrikeout()) {
startStrikeoutIndex = index;
isStrikeoutStartIndex = true;
if (i + 1 == cnt) {
// 最後の塊の場合はここで出力する。
System.out.println(cellStr.substring(startStrikeoutIndex, cellStr.length()));
}
}
}
}
根据我调查的内容,我使用了可用的处理方法进行实现,结果变得非常笨拙。简单来解释一下原理,以“あいうえお”为例,取得带有删除线的部分的第一个字符的索引作为“startStrikeoutIndex”(例如,当为“い”时索引为1),并将“isStrikeoutStartIndex”设为true。然后,如果“isStrikeoutStartIndex”为true,那么在“startStrikeoutIndex”和该块的下一个块的第一个字符索引(例如,对于“う”部分,索引为2)之间的字符将成为被删除线划掉的文字,因此我们取得该部分内容。
最后
因为这是一个相当艰苦的部分,所以我整理了一份可以在需要时回顾的资料。如果能对有同样想法的人有所帮助,那将更加令我高兴。
请在中文中提供一个这个句子的同义表达。
- Excelシート内の「取り消し線(打ち消し線)」設定の判定の仕方