CellFinder.java

  1. package com.gh.mygreen.xlsmapper.util;

  2. import java.util.Optional;

  3. import org.apache.poi.ss.usermodel.Cell;
  4. import org.apache.poi.ss.usermodel.Row;
  5. import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
  6. import org.apache.poi.ss.usermodel.Sheet;

  7. import com.gh.mygreen.xlsmapper.Configuration;
  8. import com.gh.mygreen.xlsmapper.fieldprocessor.CellNotFoundException;

  9. /**
  10.  * 指定したラベルを持つセルを検索するクラス。
  11.  *
  12.  * @since 2.0
  13.  * @author T.TSUCHIE
  14.  *
  15.  */
  16. public class CellFinder {
  17.    
  18.    
  19.     /**
  20.      * シート情報
  21.      */
  22.     private final Sheet sheet;
  23.    
  24.     /**
  25.      * システム設定
  26.      */
  27.     private final Configuration config;
  28.    
  29.     /**
  30.      * 検索対象のラベル
  31.      */
  32.     private final String label;
  33.    
  34.     /**
  35.      * 起点となる行番号
  36.      * ・指定しない場合は、-1を指定する
  37.      */
  38.     private int startRow = -1;
  39.    
  40.     /**
  41.      * 起点となる列番号
  42.      * ・指定しない場合は、-1を指定する
  43.      */
  44.     private int startColumn = -1;
  45.    
  46.     /**
  47.      * 起点となる位置を除外するかどうか
  48.      */
  49.     private boolean excludeStartPoisition = false;
  50.    
  51.     /**
  52.      * 検索する際の条件を組み立てる
  53.      * @param sheet 検索対象のシート
  54.      * @param label 検索するセルのラベル
  55.      * @param config システム設定。
  56.      *        設定値 {@link Configuration#isNormalizeLabelText()}、{@link Configuration#isRegexLabelText()}の値によって、
  57.      *        検索する際にラベルを正規化、または正規表現により一致するかで判定を行う。
  58.      */
  59.     public static CellFinder query(final Sheet sheet, final String label, final Configuration config) {
  60.         return new CellFinder(sheet, label, config);
  61.     }
  62.    
  63.     private CellFinder(final Sheet sheet, final String label, final Configuration config) {
  64.        
  65.         ArgUtils.notNull(sheet, "sheet");
  66.         ArgUtils.notEmpty(label, "label");
  67.         ArgUtils.notNull(config, "config");
  68.        
  69.         this.sheet = sheet;
  70.         this.label = label;
  71.         this.config = config;
  72.     }
  73.    
  74.     /**
  75.      * 起点なる位置を指定する。
  76.      * @param column 列番号(0から始まる)
  77.      * @param row 行番号(0から始まる)
  78.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  79.      * @throws IllegalArgumentException {@literal column < 0 or row < 0}
  80.      */
  81.     public CellFinder startPosition(final int column, final int row) {
  82.         ArgUtils.notMin(column, 0, "column");
  83.         ArgUtils.notMin(row, 0, "row");
  84.        
  85.         this.startColumn = column;
  86.         this.startRow = row;
  87.        
  88.         return this;
  89.     }
  90.    
  91.     /**
  92.      * 起点なる位置を指定する。
  93.      * @param cell 起点とうなるセル
  94.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  95.      * @throws NullPointerException {@literal cell == null.}
  96.      */
  97.     public CellFinder startPosition(final Cell cell) {
  98.         ArgUtils.notNull(cell, "cell");
  99.        
  100.         return startPosition(cell.getColumnIndex(), cell.getRowIndex());
  101.     }
  102.    
  103.     /**
  104.      * 起点なる位置を指定する。
  105.      * @param address セルのアドレス
  106.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  107.      * @throws NullPointerException {@literal address == null.}
  108.      */
  109.     public CellFinder startPosition(final CellPosition address) {
  110.         ArgUtils.notNull(address, "address");
  111.        
  112.         return startPosition(address.getColumn(), address.getRow());
  113.     }
  114.    
  115.     /**
  116.      * 起点となる列を指定する。
  117.      * ただし、行は先頭から検索する。
  118.      * @param column 列番号(0から始まる)
  119.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  120.      * @throws IllegalArgumentException {@literal column < 0}
  121.      */
  122.     public CellFinder startColumn(final int column) {
  123.         ArgUtils.notMin(column, 0, "column");
  124.        
  125.         this.startColumn = column;
  126.         this.startRow = -1;
  127.        
  128.         return this;
  129.     }
  130.    
  131.     /**
  132.      * 起点となる行を指定する。
  133.      * ただし、列は先頭から検索する。
  134.      * @param row 行番号(0から始まる)
  135.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  136.      * @throws IllegalArgumentException {@literal row < 0}
  137.      */
  138.     public CellFinder startRow(final int row) {
  139.         ArgUtils.notMin(row, 0, "row");
  140.        
  141.         this.startColumn = -1;
  142.         this.startRow = row;
  143.        
  144.         return this;
  145.     }
  146.    
  147.     /**
  148.      * 起点となる位置を除外するかどうか。
  149.      * @param excludeStartPosition trueの場合、起点となる位置を除外する
  150.      * @return 自身のインスタンス。メソッドチェーンとして続ける。
  151.      */
  152.     public CellFinder excludeStartPosition(final boolean excludeStartPosition) {
  153.         this.excludeStartPoisition = excludeStartPosition;
  154.         return this;
  155.     }
  156.    
  157.     /**
  158.      * 一致する条件のセルを探す。
  159.      * @return 見つからない場合は、空を返す。
  160.      */
  161.     public Optional<Cell> findOptional() {
  162.        
  163.         return Optional.ofNullable(findCell());
  164.        
  165.     }
  166.    
  167.     /**
  168.      * 一致する条件のセルを探す。
  169.      * ただし、指定したセルが見つからない場合は、例外{@link CellNotFoundException}をスローする。
  170.      * @return
  171.      * @throws CellNotFoundException 指定したセルが見つからない場合
  172.      */
  173.     public Cell findWhenNotFoundException() {
  174.        
  175.         final Cell cell = findCell();
  176.         if(cell == null) {
  177.             throw new CellNotFoundException(sheet.getSheetName(), label);
  178.         }
  179.        
  180.         return cell;
  181.        
  182.     }
  183.    
  184.     /**
  185.      * 一致する条件のセルを探す。
  186.      * @param optional セルが見つからない場合に、nullを返すかどうか。
  187.      * @return 一致したセルを返す。
  188.      * @throws CellNotFoundException 引数「optional=false」のときに、一致するセルが見つからない場合にスローする。
  189.      */
  190.     public Cell find(final boolean optional) {
  191.         if(optional) {
  192.             return findOptional().orElse(null);
  193.         } else {
  194.             return findWhenNotFoundException();
  195.         }
  196.     }
  197.    
  198.     /**
  199.      * 条件に一致するセルを探す
  200.      * @return 見つからない場合は、nullを返す。
  201.      */
  202.     private Cell findCell() {
  203.        
  204.         final int rowStart = startRow < 0 ? 0 : startRow;
  205.         final int columnStart = startColumn < 0 ? 0 : startColumn;
  206.        
  207.         final int maxRow = POIUtils.getRows(sheet);
  208.         for(int i=rowStart; i < maxRow; i++) {
  209.             final Row row = sheet.getRow(i);
  210.             if(row == null) {
  211.                 continue;
  212.             }
  213.            
  214.             final int maxCol = row.getLastCellNum();;
  215.             for(int j=columnStart; j < maxCol; j++) {
  216.                
  217.                 if(excludeStartPoisition && includeInStartPosition(j, i)) {
  218.                     // 開始位置を除外する場合
  219.                     continue;
  220.                 }
  221.                
  222.                 final Cell cell = row.getCell(j, MissingCellPolicy.CREATE_NULL_AS_BLANK);
  223.                 final String cellValue = POIUtils.getCellContents(cell, config.getCellFormatter());
  224.                 if(Utils.matches(cellValue, label, config)) {
  225.                     return cell;
  226.                 }
  227.             }
  228.         }
  229.        
  230.         return null;
  231.        
  232.     }
  233.    
  234.     /**
  235.      * 現在の位置が検索対象の開始位置を含むかどうか判定します。
  236.      * @param currentColumn 現在の列番号
  237.      * @param currentRow 現在の行番号
  238.      * @return trueの場合含みます。
  239.      */
  240.     private boolean includeInStartPosition(final int currentColumn, final int currentRow) {
  241.        
  242.         if(startColumn >=0 && startRow >= 0
  243.                 && currentColumn == startColumn && currentRow == startRow) {
  244.             // 行と列の両方の指定がある場合
  245.             return true;
  246.            
  247.         } else if(startColumn >= 0 && startRow < 0 && currentColumn == startColumn) {
  248.             // 列の指定のみ
  249.             return true;
  250.            
  251.         } else if(startColumn < 0 && startRow >= 0 && currentRow == startRow) {
  252.             // 行の指定のみ
  253.             return true;
  254.            
  255.         }
  256.        
  257.         return false;
  258.        
  259.     }
  260.    
  261. }