Как я могу прочитать числовые строки в ячейках Excel как строки (не числа)?

146
  1. У меня есть файл Excel с таким содержимым:

    • A1: SomeString

    • A2: 2

    Все поля имеют строковый формат.

  2. Когда я читаю файл в Java, используя POI, он говорит, что A2 в числовом формате ячейки.

  3. Проблема в том, что значение в A2 может быть 2 или 2,0 (и я хочу иметь возможность их различать), поэтому я не могу просто использовать .toString().

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

joycollector
источник

Ответы:

319

У меня была такая же проблема. Я сделал cell.setCellType(Cell.CELL_TYPE_STRING);перед чтением строкового значения, что решило проблему независимо от того, как пользователь отформатировал ячейку.

Виль
источник
Я использую poi-3.8-beta4, и он работает как положено! Почему TS не принимает это как ответ?
swdev
Имейте в виду, что преобразование числовых значений в строку POI не учитывает языковой стандарт системы, а всегда использует точку в качестве десятичного разделителя. Например, если ваша система использует «,», а в Excel числа выглядят как «1,9», POI будет возвращать «1,9».
Алексей Березкин
53
Обратите внимание, что Javadocs в Apache POI явно не делают этого! Как они объясняют, вы должны вместо этого использовать DataFormatter
Gagravarr
6
Предупреждение Гаграварра против этого - правильно! Из документов: «Если вы хотите получить строковое значение для вашей числовой ячейки, остановитесь!. Это не способ сделать это. Вместо этого для извлечения строкового значения числовой или логической ячейки или ячейки даты используйте Вместо DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Я сам использовал эту технику, пока не попал в случайное изменение данных, которые я не собирался менять. (Установите для типа значение String, прочитайте значение, установите тип обратно в числовое значение, прочитайте снова и получите другое числовое значение!)
Крис Финли,
6
Используйте DataFormatter. Javadoc предупреждает нас от использования вышеуказанного метода.
Balu SKT
96

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

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

В вашем случае я бы предположил, что к числовым ячейкам применяется правило целочисленного форматирования. Если вы попросите DataFormatter отформатировать эти ячейки, он вернет вам строку с целочисленной строкой.

Кроме того, обратите внимание, что многие люди предлагают делать это cell.setCellType(Cell.CELL_TYPE_STRING), но JavaDocs Apache POI совершенно ясно заявляют, что вы не должны этого делать ! Выполнение setCellTypeвызова приведет к потере форматирования, поскольку javadocs объясняют, что единственный способ преобразовать строку в оставшееся форматирование - это использовать класс DataFormatter .

Gagravarr
источник
Спасибо @Gagravarr, только ваш ответ работает для меня, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> в преобразовании значения 2.2 как 2.2000000000000002, но я хочу 2.2. он возвращает что-либо в строковом формате, спасибо
ankush yadav
dataformatter, похоже, не работает для ячеек формулы, он возвращает строковое представление формулы вместо значения
gaurav5430
1
Только одно небольшое замечание: пожалуйста, предоставьте короткие фрагменты кода для таких ответов, также, если они указаны в предоставленных ссылках
BAERUS
@ gaurav5430 Да, это не очень хорошо с формулами ... Согласно документу,When passed a null or blank cell, this method will return an empty String (""). Formulas in formula type cells will not be evaluated.
SaratBhaswanth
53

Приведенный ниже код работал для меня для любого типа клеток.

InputStream inp =getClass().getResourceAsStream("filename.xls"));
Workbook wb = WorkbookFactory.create(inp);
DataFormatter objDefaultFormat = new DataFormatter();
FormulaEvaluator objFormulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) wb);

Sheet sheet= wb.getSheetAt(0);
Iterator<Row> objIterator = sheet.rowIterator();

while(objIterator.hasNext()){

    Row row = objIterator.next();
    Cell cellValue = row.getCell(0);
    objFormulaEvaluator.evaluate(cellValue); // This will evaluate the cell, And any type of cell will return string value
    String cellValueStr = objDefaultFormat.formatCellValue(cellValue,objFormulaEvaluator);

}
Винаяк Дорнала
источник
4
Работало просто отлично! Я бы предложил изменить способ извлечения FormulaEvaluator. Класс Workbook предоставляет getCreationHelper().createFormulaEvaluator()метод оценки формулы через метод. Таким образом, ваш код не будет связан с классом HSSFFormulaEvaluator.
Витор Сантос
Это должен быть принятый ответ. Спасибо @Vinayak
Phas1c
Можно FormulaEvaluatorпросто удалить из этого решения? Это служит цели?
P.Brian.Mackey
1
вызов objFormulaEvaluator.evaluate не требуется. Возвращаемое значение этого здесь не используется.
Раду Симионеску
32

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

if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
    String str = NumberToTextConverter.toText(cell.getNumericCellValue())
}

NumberToTextConverter может правильно преобразовать двойное значение в текст, используя правила Excel без потери точности.

Станислав Мамонтов
источник
Действительно захватывающий совет! Спасибо! Это позволяет получать неконвертированные значения в отличие от установки типа cellType в String.
Глеб Егунов
Я получаю 44007 в качестве вывода для значения ячейки 25/06/2020. Что я делаю не так?
Винай
10

Да, это работает отлично

рекомендуемые:

        DataFormatter dataFormatter = new DataFormatter();
        String value = dataFormatter.formatCellValue(cell);

старый:

cell.setCellType(Cell.CELL_TYPE_STRING);

даже если у вас есть проблема с получением значения из cellформулы, все равно это работает.

Раджеш Мбм
источник
5
Но вы должны быть осторожны, используя это для двойных значений. Для меня это превратило значение 7,9 в 7,8999956589965 ...
Крис
2
В javadocs Apache POI совершенно ясно, что вы не должны делать это так : если вы хотите получить значение String для вашей числовой ячейки, остановитесь !. Это не способ сделать это. Вместо этого для извлечения строкового значения числовой или логической ячейки или ячейки даты используйте вместо этого DataFormatter.
Гаграварр
4

Пытаться:

new java.text.DecimalFormat("0").format( cell.getNumericCellValue() )

Должен правильно отформатировать номер.

я беру
источник
Как я понимаю, спрашивающий хочет уметь различать 2и 2.0. Ваше решение не будет делать это. (Но, тем не менее, добро пожаловать в Stack Overflow!)
Paŭlo Ebermann
1

Пока ячейка находится в текстовом формате, прежде чем пользователь введет число, POI позволит вам получить значение в виде строки. Одним из ключей является то, что если в верхнем левом углу ячейки, отформатированной как текст, есть маленький зеленый треугольник, вы сможете получить его значение в виде строки (зеленый треугольник появляется всякий раз, когда что-то выглядит как число приведен в текстовый формат). Если у вас есть ячейки в формате Text, содержащие числа, но POI не позволит вам извлекать эти значения в виде строк, есть несколько вещей, которые вы можете сделать с данными электронной таблицы, чтобы:

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

Последнее, что вы можете сделать, это то, что если вы используете POI для получения данных из электронной таблицы Excel 2007, вы можете использовать метод класса getRawValue () класса Cell. Это не волнует, что формат. Он просто вернет строку с необработанными данными.

Марк Фарнсворт
источник
0

Когда мы читаем числовое значение ячейки MS Excel, используя библиотеку Apache POI, оно читается как числовое. Но иногда мы хотим, чтобы он читался как строка (например, номера телефонов и т. Д.). Вот как я это сделал:

  1. Вставьте новый столбец с первой ячейкой = CONCATENATE ("!", D2). Я предполагаю, что D2 - это идентификатор ячейки вашего номера телефона. Перетащите новую ячейку до конца.

  2. Теперь, если вы читаете ячейку с помощью POI, она будет читать формулу вместо вычисленного значения. Теперь сделайте следующее:

  3. Добавить другой столбец

  4. Выберите полный столбец, созданный на шаге 1. и выберите «Правка» -> «КОПИЯ»

  5. Перейдите в верхнюю ячейку столбца, созданного на шаге 3. и выберите «Правка» -> «Специальная вставка».

  6. В открывшемся окне установите переключатель «Значения»

  7. Выберите «ОК»

  8. Теперь читайте, используя POI API ... после чтения в Java ... просто удалите первый символ, т.е. "!"

Асиф Шахзад
источник
Кажется, ваше решение не пригодно для использования, если вы сами не создаете файлы Excel, не так ли? (Кроме того, не могли бы вы вставить выдержку в свой ответ? Это не так долго.)
Paŭlo Ebermann
Да, его нельзя использовать, если вы сами не создаете файл Excel.
Асиф Шахзад
0

У меня также была похожая проблема с набором данных из тысяч номеров, и я думаю, что нашел простой способ решения. Мне нужно было вставить апостроф перед числом, чтобы отдельный импорт БД всегда рассматривал числа как текст. До этого число 8 будет импортировано как 8.0.

Решение:

  • Сохраняйте все форматирование как общее.
  • Здесь я предполагаю, что числа хранятся в столбце А, начиная с строки 1.
  • Вставьте 'в столбце B и скопируйте столько строк, сколько необходимо. На рабочем листе ничего не появляется, кроме щелчка по ячейке, вы можете увидеть апостоф на панели формул.
  • В столбце C: = B1 и A1.
  • Выберите все ячейки в столбце C и выполните специальную вставку в столбец D, используя параметр «Значения».

Привет Престо все числа, но хранятся в виде текста.

Марк Холмс
источник
0

getStringCellValue возвращает NumberFormatException, если тип ячейки числовой. Если вы не хотите менять тип ячейки на строку, вы можете сделать это.

String rsdata = "";
try {
    rsdata = cell.getStringValue();
} catch (NumberFormatException ex) {
    rsdata = cell.getNumericValue() + "";
}
zawhtut
источник
0

Многие из этих ответов ссылаются на старую документацию и классы POI. В новейшей POI 3.16 ячейка с типами int устарела

Cell.CELL_TYPE_STRING

введите описание изображения здесь

Вместо этого можно использовать перечисление CellType .

CellType.STRING 

Просто убедитесь, что ваш pom обновлен с зависимостью poi, а также с зависимостью poi-ooxml до новой версии 3.16, иначе вы будете продолжать получать исключения. Одним из преимуществ этой версии является то, что вы можете указать тип ячейки во время ее создания, исключив все дополнительные шаги, описанные в предыдущих ответах:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);
Nelda.techspiress
источник
0

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

for (Row row : sheet){
String strValue = (row.getCell(numericColumn)+""); // hack
...

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

Сноска: numericColumn - это int, который генерируется из чтения заголовка обработанного файла.

KeaganFouche
источник
0
public class Excellib {
public String getExceldata(String sheetname,int rownum,int cellnum, boolean isString) {
    String retVal=null;
    try {
        FileInputStream fis=new FileInputStream("E:\\Sample-Automation-Workspace\\SampleTestDataDriven\\Registration.xlsx");
        Workbook wb=WorkbookFactory.create(fis);
        Sheet s=wb.getSheet(sheetname);
        Row r=s.getRow(rownum);
        Cell c=r.getCell(cellnum);
        if(c.getCellType() == Cell.CELL_TYPE_STRING)
        retVal=c.getStringCellValue();
        else {
            retVal = String.valueOf(c.getNumericCellValue());
        }

Я попробовал это, и у меня это сработало

Prasanna
источник
-1

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

datatoo
источник
-1

Это сработало идеально для меня.

Double legacyRow = row.getCell(col).getNumericCellValue();
String legacyRowStr = legacyRow.toString();
if(legacyRowStr.contains(".0")){
    legacyRowStr = legacyRowStr.substring(0, legacyRowStr.length()-2);
}
Рама Кришна
источник
-2

У нас была та же проблема, и мы заставляли пользователей форматировать ячейки как «текст» перед вводом значения. Таким образом, Excel правильно сохраняет четные числа в виде текста. Если впоследствии формат изменяется, Excel только изменяет способ отображения значения, но не меняет способ хранения значения, пока значение не будет введено снова (например, путем нажатия клавиши возврата в ячейке).

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

Turismo
источник
-3

приведите к int, затем сделайте .toString(). Это некрасиво, но это работает.

WolfmanDragon
источник
Проблема в том, что если в A2 есть 2.0, мне нужно получить строку «2.0», а если 2, то строку «2».
joycollector