Obtenga el valor de celda como se presentó en excel

Actualmente estoy trabajando en un proyecto que lee un archivo Excel utilizando Apache POI.

Mi tarea parece ser simple, solo necesito obtener el valor de la celda tal como se muestra en el archivo de Excel. Soy consciente de realizar una statement de cambio basada en el tipo de celda de una celda. Pero si los datos son algo así como

9,000.00

POI me da 9000.0 cuando getNumericCellValue() . Cuando obligo a la celda a ser un tipo de cadena y hago getStringCellValue() , entonces me da 9000 . Lo que necesito es la información de cómo se presentó en Excel.

Encontré algunos mensajes que decían usar la clase DataFormat pero, según mi entendimiento, requiere que el código tenga en cuenta el formato que tiene la celda. En mi caso, no conozco el formato que podría tener la celda.

Entonces, ¿cómo puedo recuperar el valor de la celda como se presentó en Excel?

Excel almacena algunas celdas como cadenas, pero la mayoría como números con reglas de formato especiales aplicadas a ellas. Lo que tendrá que hacer es hacer que esas reglas de formato se ejecuten contra las celdas numéricas, para producir cadenas que se vean como lo hacen en Excel.

Afortunadamente, Apache POI tiene una clase para hacer precisamente eso: DataFormatter

Todo lo que necesitas hacer es algo como:

  Workbook wb = WorkbookFactory.create(new File("myfile.xls")); DataFormatter df = new DataFormatter(); Sheet s = wb.getSheetAt(0); Row r1 = s.getRow(0); Cell cA1 = r1.getCell(0); String asItLooksInExcel = df.formatCellValue(cA1); 

No importa cuál sea el tipo de celda, DataFormatter lo formateará lo mejor que pueda, utilizando las reglas aplicadas en Excel

De hecho, nunca es posible obtener exactamente el valor de celda formateado con la configuración regional definida cuando se escribió la celda. se debe al observador local y al hecho de que el prefijo local de Excel no se vuelve a utilizar al formatearlo después;

Análisis para POI 3.17 (puede cambiar desde que se observa cómo el componente se realiza internamente)

por ejemplo: el formato dateConverted del estilo de celda (de CellStyle.getDataFormatString ()) para Locale.US con el formato dd MMM aaaa hh: mm: ss es:
“[$ -0409] dd MMM aaaa hh: mm: ss; @” donde el prefijo interno excel local = [$ -0409]

Se obtiene a partir del mapa estático privado DateFormatConverter.localPrefixes.

aquí hay un código para solucionar este problema:

 /** * Missing method in POI to enable the visualisation asIs of an cell with a * different locale in a xls document. * * @param style * the cell style localized. * @return the Locale found using internal locationPrefixes. */ private final Locale extractLocaleFromDateCellStyle(final CellStyle style) { final String reOpenedFormat = style.getDataFormatString(); LOGGER.info("Data Format of CellStyle : " + reOpenedFormat); Locale locale = getLocaleFromPrefixes(extractPrefixeFromPattern(reOpenedFormat)); LOGGER.info("Found locale : " + locale); return locale; } /** * Extracts the internal prefix that represent the local of the style. * * @param pattern * the DataFormatString of the cell style. * @return the prefix found. */ private final String extractPrefixeFromPattern(final String pattern) { Pattern regex = Pattern.compile(REGEX_PREFIX_PATTERN); Matcher match = regex.matcher(pattern); if (match.find()) { LOGGER.info("Found prefix: " + match.group(1)); // return only the prefix return match.group(1); } return null; } /** * Reverse obtain the locale from the internal prefix from * DateFormatConverter.localePrefixes private static field. * 

* Uses reflection API. * * @param prefixes * the prefixes * @return the local corresponding tho the prefixes. */ public static Locale getLocaleFromPrefixes(final String prefixes) { try { @SuppressWarnings("unchecked") Map map = getStaticPrivateInternalMapLocalePrefix(); String localPrefix = null; // find the language_Country value matching the internal excel // prefix. for (Map.Entry entry : map.entrySet()) { LOGGER.info("value : " + entry.getValue() + ", key :" + entry.getKey()); if (entry.getValue().equals(prefixes) && !StringUtils.isBlank(entry.getKey())) { localPrefix = entry.getKey(); break; } } // Generate a Locale with language, uppercase(country) info. LOGGER.info(localPrefix); if (localPrefix.indexOf('_') > 0) { String[] languageCountry = localPrefix.split("_"); return new Locale(languageCountry[0], StringUtils.defaultString(languageCountry[1] .toUpperCase())); } // nothing found. return null; // factorized the multiples exceptions. } catch (Exception e) { throw new UnsupportedOperationException(e); } } /** * gets the internal code map for locale used by Excel. * * @return the internal map. * @throws NoSuchFieldException * if the private field name changes. * @throws IllegalAccessException * if the accessible is restricted. */ private static Map getStaticPrivateInternalMapLocalePrefix() throws NoSuchFieldException, IllegalAccessException { // REFLECTION Class clazz = DateFormatConverter.class; Field fieldlocalPrefixes = (Field) clazz .getDeclaredField(DATE_CONVERTER_PRIVATE_PREFIXES_MAP); // change from private to public. fieldlocalPrefixes.setAccessible(true); @SuppressWarnings("unchecked") Map map = (Map) fieldlocalPrefixes .get(clazz); LOGGER.info("MAP localPrefixes : " + map); return map; }

Por lo tanto, el siguiente código simple debería hacer el truco. Tenga en cuenta que el código no está completamente probado con valores nulos y depende de la versión de POI que utilice hasta que haya cambiado LOCAL OBSERVER MADNESS 🙂

  .... final CellStyle cellStyle = reopenedCell.getCellStyle(); Locale locale = extractLocaleFromDateCellStyle(cellStyle); LOGGER.info("FOUND LOCAL : " + locale); // use the same local from the cell style during writing. DataFormatter df = new DataFormatter(locale); String reOpenValue = df.formatCellValue(reopenedCell); 

Saludos.

Use el CellType , puede verificar todo

 if (cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC) 

// el CellValue es numérico

 if (cellValue.getCellType() == Cell.CELL_TYPE_STRING) 

// el cellValue es una cadena

la fecha también se da como numérica, en ese momento verifica que la celda dada sea o no con dateUtil

 if (DateUtil.isCellDateFormatted(cellData)) 

después de que puedas convertir el valor de celda en la fecha