1919package org .spacious_team .table_wrapper .excel ;
2020
2121import org .apache .poi .ss .usermodel .Cell ;
22- import org .apache .poi .ss .usermodel .CellType ;
22+ import org .apache .poi .ss .usermodel .FormulaError ;
2323import org .apache .poi .ss .usermodel .Row ;
2424import org .apache .poi .ss .usermodel .Sheet ;
2525import org .apache .poi .ss .util .CellAddress ;
2626import org .spacious_team .table_wrapper .api .TableCellAddress ;
2727
28- import java .util .function . BiPredicate ;
28+ import java .util .Objects ;
2929import java .util .function .Predicate ;
3030
3131import static org .spacious_team .table_wrapper .api .TableCellAddress .NOT_FOUND ;
3232
3333class ExcelTableHelper {
3434
3535 /**
36- * @param value searching value
37- * @param startRow search rows start from this
38- * @param endRow search rows excluding this, can handle values greater than real rows count
36+ * @param value searching value
37+ * @param startRow search rows start from this
38+ * @param endRow search rows excluding this, can handle values greater than real rows count
3939 * @param startColumn search columns start from this
40- * @param endColumn search columns excluding this, can handle values greater than real columns count
40+ * @param endColumn search columns excluding this, can handle values greater than real columns count
4141 * @return table cell address or {@link TableCellAddress#NOT_FOUND}
4242 */
43- static TableCellAddress find (Sheet sheet , Object value , int startRow , int endRow ,
43+ static TableCellAddress find (Sheet sheet , Object value ,
44+ int startRow , int endRow ,
45+ int startColumn , int endColumn ) {
46+ Object expected = (value instanceof Number ) ?
47+ ((Number ) value ).doubleValue () : // excel store Numbers as doubles
48+ value ;
49+ return find (sheet , startRow , endRow , startColumn , endColumn , (cell ) -> equals (cell , expected ));
50+ }
51+
52+ /**
53+ * @param startRow search rows start from this
54+ * @param endRow search rows excluding this, can handle values greater than real rows count
55+ * @param startColumn search columns start from this
56+ * @param endColumn search columns excluding this, can handle values greater than real columns count
57+ * @return table cell address or {@link TableCellAddress#NOT_FOUND}
58+ */
59+ static TableCellAddress find (Sheet sheet , int startRow , int endRow ,
4460 int startColumn , int endColumn ,
45- BiPredicate <String , Object > stringPredicate ) {
46- if (sheet .getLastRowNum () == -1 ) {
47- return NOT_FOUND ;
48- } else if (endRow > sheet .getLastRowNum ()) {
49- endRow = sheet .getLastRowNum () + 1 ; // endRow is exclusive
50- }
51- CellType type = getType (value );
52- if (type == CellType .NUMERIC ) {
53- value = ((Number ) value ).doubleValue ();
54- }
55- for (int rowNum = startRow ; rowNum < endRow ; rowNum ++) {
61+ Predicate <Cell > predicate ) {
62+ startRow = Math .max (0 , startRow );
63+ endRow = Math .min (endRow , sheet .getLastRowNum () + 1 ); // endRow is exclusive
64+ for (int rowNum = startRow ; rowNum < endRow ; rowNum ++) {
5665 Row row = sheet .getRow (rowNum );
5766 if (row == null ) continue ;
5867 for (Cell cell : row ) {
5968 if (cell != null ) {
6069 int column = cell .getColumnIndex ();
61- if (startColumn <= column && column < endColumn && cell . getCellType () == type ) {
62- if (compare ( value , cell , stringPredicate )) {
70+ if (startColumn <= column && column < endColumn ) {
71+ if (predicate . test ( cell )) {
6372 CellAddress address = cell .getAddress ();
6473 return new TableCellAddress (address .getRow (), address .getColumn ());
6574 }
@@ -70,43 +79,36 @@ static TableCellAddress find(Sheet sheet, Object value, int startRow, int endRow
7079 return NOT_FOUND ;
7180 }
7281
73- private static TableCellAddress findByPredicate (Sheet sheet , int startRow , Predicate <Cell > predicate ) {
74- int endRow = sheet .getLastRowNum () + 1 ;
75- for (int rowNum = startRow ; rowNum < endRow ; rowNum ++) {
76- Row row = sheet .getRow (rowNum );
77- if (row == null ) continue ;
78- for (Cell cell : row ) {
79- if (predicate .test (cell )) {
80- CellAddress address = cell .getAddress ();
81- return new TableCellAddress (address .getRow (), address .getColumn ());
82- }
83- }
84- }
85- return NOT_FOUND ;
82+ static Object getValue (Cell cell ) {
83+ return switch (cell .getCellType ()) {
84+ case STRING -> cell .getStringCellValue ();
85+ case NUMERIC -> cell .getNumericCellValue (); // returns double
86+ case BLANK -> null ;
87+ case BOOLEAN -> cell .getBooleanCellValue ();
88+ case FORMULA -> getCachedFormulaValue (cell );
89+ case ERROR -> throw new RuntimeException ("Ячейка содержит ошибку вычисления формулы: " +
90+ FormulaError .forInt (cell .getErrorCellValue ()));
91+ case _NONE -> null ;
92+ };
8693 }
8794
88- private static CellType getType (Object value ) {
89- CellType type ;
90- if (value instanceof String ) {
91- type = (((String ) value ).isEmpty ()) ? CellType .BLANK : CellType .STRING ;
92- } else if (value instanceof Number ) {
93- type = CellType .NUMERIC ;
94- } else if (value instanceof Boolean ) {
95- type = CellType .BOOLEAN ;
96- } else if (value == null ) {
97- type = CellType .BLANK ;
98- } else {
99- throw new IllegalArgumentException ("Не могу сравнить значение '" + value + "' типа " + value .getClass ().getName ());
100- }
101- return type ;
95+ private static Object getCachedFormulaValue (Cell cell ) {
96+ return switch (cell .getCachedFormulaResultType ()) {
97+ case BOOLEAN -> cell .getBooleanCellValue ();
98+ case NUMERIC -> cell .getNumericCellValue ();
99+ case STRING -> cell .getRichStringCellValue ();
100+ case ERROR -> throw new RuntimeException ("Ячейка не содержит кешированный результат формулы: " +
101+ FormulaError .forInt (cell .getErrorCellValue ()));
102+ default -> null ; // never should occur
103+ };
102104 }
103105
104- private static boolean compare ( Object value , Cell cell , BiPredicate < String , Object > stringPredicate ) {
106+ private static boolean equals ( Cell cell , Object expected ) {
105107 return switch (cell .getCellType ()) {
106- case BLANK -> value == null || value .equals ("" );
107- case STRING -> stringPredicate . test (cell .getStringCellValue (), value );
108- case NUMERIC -> (value instanceof Number ) && ( cell .getNumericCellValue () - ((Number ) value ).doubleValue ()) < 1e-6 ;
109- case BOOLEAN -> value .equals (cell .getBooleanCellValue ());
108+ case BLANK -> expected == null || expected .equals ("" );
109+ case STRING -> ( expected instanceof CharSequence ) && Objects . equals (cell .getStringCellValue (), expected . toString () );
110+ case NUMERIC -> (expected instanceof Number ) && Math . abs (( cell .getNumericCellValue () - ((Number ) expected ).doubleValue () )) < 1e-6 ;
111+ case BOOLEAN -> expected .equals (cell .getBooleanCellValue ());
110112 default -> false ;
111113 };
112114 }
0 commit comments