Вопрос:

Получить значение ячейки, как она была представлена ​​в Excel

java apache-poi

9829 просмотра

3 ответа

4142 Репутация автора

В настоящее время я работаю над проектом, который читает файл Excel с использованием Apache POI.

Моя задача проста, мне просто нужно получить значение ячейки, которое отображалось в файле Excel. Мне известно о выполнении оператора switch на основе типа ячейки ячейки. Но если данные что-то вроде

9,000.00

POI дает мне, 9000.0когда я делаю getNumericCellValue(). Когда я вынуждаю ячейку быть строковым типом и делаю getStringCellValue()это, то выдает меня 9000. Что мне нужно, так это данные о том, как они были представлены в Excel.

Я нашел пост, в котором говорится, что нужно использовать DataFormatкласс, но, насколько я понимаю, он требует, чтобы ваш код знал о формате, который имеет ячейка. В моем случае я не знаю формат, который может иметь ячейка.

Итак, как я могу получить значение ячейки, как это было представлено в Excel?

Автор: Bnrdo Источник Размещён: 16.10.2013 10:45

Ответы (3)


0 плюса

7507 Репутация автора

Используйте CellType, вы можете проверить все

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

// cellValue является числовым

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

// cellValue является строкой

дата также указывается как числовое значение, в то время проверяйте, является ли данная ячейка датой или нет с помощью dateUtil.

if (DateUtil.isCellDateFormatted(cellData))

после того, как вы можете конвертировать значение ячейки в дату

Автор: newuser Размещён: 16.10.2013 10:55

21 плюса

39046 Репутация автора

Решение

В Excel некоторые ячейки хранятся в виде строк, но чаще всего в виде чисел, к которым применяются специальные правила форматирования. Вам нужно будет запустить эти правила форматирования для числовых ячеек, чтобы получить строки, которые выглядят так же, как в Excel.

К счастью, в Apache POI есть класс для этого - DataFormatter

Все, что вам нужно сделать, это что-то вроде:

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

Неважно, какой тип ячейки, DataFormatter отформатирует его как можно лучше, используя правила, применяемые в Excel.

Автор: Gagravarr Размещён: 16.10.2013 11:12

1 плюс

11 Репутация автора

На самом деле, невозможно получить точно отформатированное значение ячейки с локалью, определенной при написании ячейки. это связано с наблюдателем локали и тем фактом, что внутренний префикс locale excel никогда не используется повторно при последующем форматировании;

Анализ для POI 3.17 (может измениться, если посмотреть, как компонент выполнен внутри)

например: dateConverted формат стиля ячейки (из CellStyle.getDataFormatString ()) для Locale.US в формате dd MMM гггг чч: мм: сс is:
"[$ -0409] дд ммм гггг чч: мм: сс; @ "где местный префикс внутреннего префикса = [$ -0409]

Он получен из частной статической карты DateFormatConverter.localPrefixes.

Вот некоторый код, чтобы обойти эту проблему:

/**
 * 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; }

Таким образом, следующий простой код должен сделать свое дело. Обратите внимание, что код не полностью протестирован с нулевыми значениями и зависит от версии POI, которую вы используете, пока они там не изменились. 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);

С уважением.

Автор: Patrice Rochemont Размещён: 20.08.2018 11:13
Вопросы из категории :
32x32