Apache POI - Leer una celda con formato por TEXT () fórmula

ner0:

Tengo un archivo EXCEL con fechas en ella. Ellos tienen el formato de texto, por ejemplo:=TEXT(TODAY(); "yyyy-MM-dd")

En Excel la fecha tiene el formato correcto como texto, pero cuando leí la célula con Apache POI, devolverá el valor numérico. ¿Por qué? ¿Por qué PDI no lee el valor de texto con formato?

No quiero dar formato a la fecha en mi aplicación Java, porque el archivo EXCEL debe definir el formato (que podría ser diferente para cada valor).

Aquí está mi código para leer el valor de la celda:

private static String getString(Cell cell) {
 if (cell == null) return null; 

 if (cell.getCellTypeEnum() != CellType.FORMULA) { 
  switch (cell.getCellTypeEnum()) { 
   case STRING: 
    return cell.getStringCellValue().trim(); 
   case BOOLEAN: 
    return String.valueOf(cell.getBooleanCellValue());
   case NUMERIC: 
    return String.valueOf(cell.getNumericCellValue()); 
   case BLANK: 
    return null; 
   case ERROR: 
    throw new RuntimeException(ErrorEval.getText(cell.getErrorCellValue())); 
   default: 
    throw new RuntimeException("unexpected cell type " + cell.getCellTypeEnum());
  }
 } 
 FormulaEvaluator evaluator = cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator();
 try { 
  CellValue cellValue = evaluator.evaluate(cell); 
  switch (cellValue.getCellTypeEnum()) { 
   case NUMERIC: 
    return String.valueOf(cellValue.getNumberValue());
   case STRING: 
    return cellValue.getStringValue().trim(); 
   case BOOLEAN: 
    return String.valueOf(cellValue.getBooleanValue()); 
   case ERROR: 
    throw new RuntimeException(ErrorEval.getText(cellValue.getErrorValue())); 
   default: 
    throw new RuntimeException("unexpected
cell type " + cellValue.getCellTypeEnum()); 
  } 
 } catch (RuntimeException e) { 
  throw new RuntimeException("Could not evaluate the value of " + cell.getAddress() + " in sheet " + cell.getSheet().getSheetName(), e);
 }
}
Axel Richter:

El problema sólo se produce si el Excelusado no es un ser Inglés. A continuación, la fórmula no es realmente =TEXT(A2,"yyyy-MM-dd")por ejemplo, pero =TEXT(A2,"JJJJ-MM-TT")en mi alemán Excel, por ejemplo.

Como se ve, la parte de formato dentro de la TEXTfunción será siempre depende del local a pesar de todas las otras partes de la fórmula serán configuración en_US siempre. Esto se debe a que el formato es parte de una cadena dentro de la fórmula que no será cambiado. Así que en alemán es =TEXT(A2,"JJJJ-MM-TT")(Año = Jahr, Día = Tag) y en francés es =TEXT(A2,"AAAA-MM-JJ")(Año = Année, Día = Jour).

Y debido a que apache poi's FormulaEvaluatorno tiene opciones de localización hasta ahora, que la fórmula no puede ser evaluado correctamente.

Entonces tenemos dos posibilidades.

En primer lugar lo que podría esperar el valor de celda almacenado debe ser la cadena sea necesario. Así que si fórmula de celda comienza con "TEXTO" y contiene "JJJJ-MM-TT", entonces no evaluando porque esto no será correctamente. En su lugar tomar el valor de la celda cadena desde Excella última evaluación 's.

En segundo lugar podríamos sustitución de la pieza de formato dependiente de la localidad con el en_US en la fórmula y luego dejar que apache poievaluar. Al menos si sólo quiere leer y no volver a escribir el Excelarchivo de esto no destroing algo en el Excelarchivo.


Código primera aproximación:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.*;

import org.apache.poi.ss.formula.eval.ErrorEval;

import java.io.FileInputStream;

class ReadExcelExample {

 private static String getString(Cell cell, FormulaEvaluator evaluator) {
  if (cell == null) return "null";
  String text = "";
  switch (cell.getCellType()) {
  //switch (cell.getCellTypeEnum()) {
   case STRING:
    text = cell.getRichStringCellValue().getString();
   break;
   case NUMERIC:
    if (DateUtil.isCellDateFormatted(cell)) {
     text = String.valueOf(cell.getDateCellValue());
    } else {
     text = String.valueOf(cell.getNumericCellValue());
    }
   break;
   case BOOLEAN:
    text = String.valueOf(cell.getBooleanCellValue());
   break;
   case FORMULA:
    text = cell.getCellFormula();

    //if formula is TEXT(...,"JJJJ-MM-TT") then do not evaluating:
    if (cell.getCellFormula().startsWith("TEXT") && cell.getCellFormula().contains("JJJJ-MM-TT")) {
     text = text + ": value got from cell = " + cell.getRichStringCellValue().getString();

    } else {
     CellValue cellValue = evaluator.evaluate(cell); 
     switch (cellValue.getCellType()) {
     //switch (cellValue.getCellTypeEnum()) {
      case STRING:
       text = text + ": " + cellValue.getStringValue();
      break;
      case NUMERIC:
       if (DateUtil.isCellDateFormatted(cell)) {
        text = text + ": " + String.valueOf(DateUtil.getJavaDate(cellValue.getNumberValue()));
       } else {
        text = text + ": " + String.valueOf(cellValue.getNumberValue());
       }
      break;
      case BOOLEAN:
       text = text + ": " + String.valueOf(cellValue.getBooleanValue());
      break;
      case ERROR:
       throw new RuntimeException("from CellValue: " + ErrorEval.getText(cellValue.getErrorValue()));
      default:
       throw new RuntimeException("unexpected cellValue type " + cellValue.getCellType()); 
     }
    }
   break;
   case ERROR:
    throw new RuntimeException("from Cell: " + ErrorEval.getText(cell.getErrorCellValue())); 
   case BLANK:
    text = "";
   break;
   default:
    throw new RuntimeException("unexpected cell type " + cell.getCellType());
  }

  return text;
 }

 public static void main(String[] args) throws Exception {

  //Workbook wb  = WorkbookFactory.create(new FileInputStream("SAMPLE.xls"));
  Workbook wb  = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));

  DataFormatter formatter = new DataFormatter(new java.util.Locale("en", "US"));
  FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();

  Sheet sheet = wb.getSheetAt(0);
  for (Row row : sheet) {
   for (Cell cell : row) {
    CellReference cellRef = new CellReference(row.getRowNum(), cell.getColumnIndex());
    System.out.print(cellRef.formatAsString());
    System.out.print(" - ");

    String text = "";
    try {
    text = getString(cell, evaluator);
    } catch (Exception ex) {
     text = ex.toString();
    }
    System.out.println(text);

   }
  }

  wb.close();

 }
}

Excel alemán:

introducir descripción de la imagen aquí

Resultado:

A1 - Value
B1 - Formula
A2 - Fri Jan 11 00:00:00 CET 2019
B2 - TEXT(A2,"JJJJ-MM-TT"): value got from cell = 2019-01-11
A3 - 123.45
B3 - A3*2: 246.9
B4 - java.lang.RuntimeException: from CellValue: #DIV/0!
B5 - TODAY(): Fri Jan 11 00:00:00 CET 2019
B6 - B5=A2: true
A7 - java.lang.RuntimeException: from CellValue: #N/A
B8 - TEXT(TODAY(),"JJJJ-MM-TT"): value got from cell = 2019-01-11

Inglés Calc:

introducir descripción de la imagen aquí

Resultado:

A1 - Value
B1 - Formula
A2 - Fri Jan 11 00:00:00 CET 2019
B2 - TEXT(A2,"yyyy-MM-dd"): 2019-01-11
A3 - 123.45
B3 - A3*2: 246.9
B4 - java.lang.RuntimeException: from CellValue: #DIV/0!
B5 - TODAY(): Fri Jan 11 00:00:00 CET 2019
B6 - B5=A2: true
A7 - java.lang.RuntimeException: from CellValue: #N/A
B8 - TEXT(TODAY(),"yyyy-MM-dd"): 2019-01-11

segundo enfoque de código (sustitución de la pieza de formato dependiente de la localidad con el en_US):

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.*;

import java.io.FileInputStream;
import java.util.Locale;

class ExcelEvaluateTEXTDiffLocales {

 private static String getString(Cell cell, DataFormatter formatter, FormulaEvaluator evaluator, Locale locale) {
  String text = "";
  if (cell.getCellType() == CellType.FORMULA) {
   String cellFormula = cell.getCellFormula();
   text += cellFormula + ":= ";

   if (cellFormula.startsWith("TEXT")) {
    int startFormatPart = cellFormula.indexOf('"');
    int endFormatPart = cellFormula.lastIndexOf('"') + 1;
    String formatPartOld = cellFormula.substring(startFormatPart, endFormatPart);
    String formatPartNew = formatPartOld;
    if ("de".equals(locale.getLanguage())) {
     formatPartNew = formatPartNew.replace("T", "D"); // Tag = Day
     // Monat = Month
     formatPartNew = formatPartNew.replace("J", "Y"); // Jahr = Year
     //...
    } else if ("fr".equals(locale.getLanguage())) {
     formatPartNew = formatPartNew.replace("J", "D"); // Jour = Day
     // Mois = Month
     formatPartNew = formatPartNew.replace("A", "Y"); // Année = Year
     //...
    } //...
    cellFormula = cellFormula.replace(formatPartOld, formatPartNew);
    cell.setCellFormula(cellFormula);
   }

  }
  try {
   text += formatter.formatCellValue(cell, evaluator);
  } catch (org.apache.poi.ss.formula.eval.NotImplementedException ex) {
   text += ex.toString();
  }

  return text;
 }

 public static void main(String[] args) throws Exception {

  //Workbook wb  = WorkbookFactory.create(new FileInputStream("SAMPLE.xls"));
  Workbook wb  = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));

  Locale locale = new Locale("fr", "CH");
  DataFormatter formatter = new DataFormatter(locale);
  FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();

  Sheet sheet = wb.getSheetAt(0);
  for (Row row : sheet) {
   for (Cell cell : row) {
    CellReference cellRef = new CellReference(row.getRowNum(), cell.getColumnIndex());
    System.out.print(cellRef.formatAsString());
    System.out.print(" - ");

    String text = "";
    text = getString(cell, formatter, evaluator, locale);

    System.out.println(text);

   }
  }

  wb.close();

 }
}

Francés Calc:

introducir descripción de la imagen aquí

Resultado:

A1 - Value
B1 - Formula
A2 - 1/11/2019
B2 - TEXT(A2,"AAAA-MM-JJ"):= 2019-01-11
A3 - 123.45
B3 - A3*2:= 246.9
B4 - 1/A4:= #DIV/0!
B5 - TODAY():= 1/12/2019
B6 - B5=A2:= FALSE
A7 - NA():= #N/A
B8 - TEXT(TODAY(),"AAAA-MM-JJ"):= 2019-01-12

PISTA: Usado apache poiversión aquí es 4.0.1. Tal vez las versiones inferiores podrían tener más problemas de evaluación.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=211366&siteId=1
Recomendado
Clasificación