Ottieni il valore della cella come è stato presentato in Excel

Attualmente sto lavorando a un progetto che legge un file excel usando il POI di Apache.

Il mio compito sembra essere semplice, ho solo bisogno di ottenere il valore della cella così come era visualizzato nel file excel. Sono consapevole di eseguire un’istruzione switch in base al tipo di cella di una cella. Ma se i dati sono qualcosa di simile

9,000.00

POI mi dà 9000.0 quando ottengo getNumericCellValue() . Quando getStringCellValue() la cella ad essere un tipo di stringa e faccio getStringCellValue() allora mi dà 9000 . Quello di cui ho bisogno sono i dati come sono stati presentati in Excel.

Ho trovato alcuni post che dicono di usare la class DataFormat ma, secondo la mia comprensione, richiede che il tuo codice sia consapevole del formato della cella. Nel mio caso, non sono a conoscenza del formato che potrebbe avere la cella.

Quindi, come posso recuperare il valore della cella come è stato presentato in Excel?

Excel memorizza alcune celle come stringhe, ma la maggior parte come numeri con speciali regole di formattazione applicate a loro. Quello che devi fare è avere queste regole di formattazione eseguite contro le celle numeriche, per produrre stringhe che assomigliano a quelle di Excel.

Fortunatamente, POI di Apache ha una class per fare proprio questo: DataFormatter

Tutto quello che devi fare è qualcosa come:

  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); 

Non importa quale sia il tipo di cella, DataFormatter lo formatterà nel miglior modo ansible, utilizzando le regole applicate in Excel

Infatti, non è mai ansible ottenere esattamente il valore di cella formattato con le impostazioni locali definite quando la cella è stata scritta. è dovuto all’osservatore delle impostazioni internazionali e al fatto che il prefisso excel della locale interna non viene mai riutilizzato durante la formattazione successiva;

Analisi per POI 3.17 (potrebbe cambiare visto il modo in cui il componente viene eseguito internamente)

per esempio: il formato dataConverted dello stile della cella (da CellStyle.getDataFormatString ()) per Locale.US con il formato gg MMM aaaa hh: mm: ss è:
“[$ -0409] dd MMM yyyy hh: mm: ss; @” dove il prefisso interno excel locale = [$ -0409]

È ottenuto da DateFormatConverter.localPrefixes mappa statica privata.

ecco un codice per aggirare questo 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; }

Quindi, il seguente semplice codice dovrebbe fare il trucco. Nota che il codice non è completamente testato con valori nulli e dipende dalla versione del PDI che utilizzi fino a quando non sono stati modificati lì LOCALE 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); 

Saluti.

Usa il CellType puoi controllare ogni cosa

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

// il valore cella è numerico

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

// il cellValue è una stringa

data è anche data come numerica, in quel momento verifica che la data cella sia data o meno usando dateUtil

 if (DateUtil.isCellDateFormatted(cellData)) 

dopo puoi convertire il valore di cella nella data