Як я можу прочитати числові рядки в клітинках Excel як рядки (а не числа)?


146
  1. У мене є файл excel з таким вмістом:

    • A1: SomeString

    • А2: 2

    Усі поля встановлені у форматі String.

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

  3. Проблема полягає в тому, що значення в A2 може бути 2 або 2,0 (і я хочу вміти їх розрізняти), тому я не можу просто використовувати .toString().

Що я можу зробити, щоб прочитати значення як рядок?

Відповіді:


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
Застереження Гаграварра проти цього робити правильно! З Документів: "Якщо ви хочете зробити, це отримати значення String для вашої числової комірки, зупиніться! Натомість DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Я сам використовував цю методику, поки не завів випадково зміни даних, які я не збирався змінювати. (Встановіть тип String, прочитайте значення, поверніть тип назад до числового читання, прочитайте ще раз і отримайте інше числове значення!)
Chris Finley

6
Використовуйте DataFormatter. Javadoc застерігає нас від використання вищевказаного методу.
Balu SKT

96

Я не думаю, що ми мали цей клас ще тоді, коли ви задавали питання, але сьогодні є проста відповідь.

Що ви хочете зробити, це використовувати клас DataFormatter . Ви передаєте цю клітинку, і вона робить все можливе, щоб повернути вам рядок, що містить те, що Excel показав би вам для цієї комірки. Якщо ви передасте йому рядкову клітинку, ви отримаєте рядок назад. Якщо ви передасте йому числову комірку із застосованими правилами форматування, вона відформатує число, засноване на них, і поверне вам рядок назад.

У вашому випадку я припускаю, що числові комірки мають ціле правило форматування до них. Якщо ви попросите DataFormatter відформатувати ці комірки, він поверне вам рядок із цілим рядком у ньому.

Також зауважте, що багато людей пропонують робити cell.setCellType(Cell.CELL_TYPE_STRING), але Apache POI JavaDocs цілком чітко стверджує, що ви не повинні цього робити ! Виконання setCellTypeдзвінка втратить форматування, оскільки javadocs пояснюють, що єдиним способом перетворення в String із залишком форматування є використання класу DataFormatter .


Дякую @Gagravarr, тільки моя відповідь працює для мене, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> в конвертувати значення 2.2 як 2.2000000000000002, але я хочу 2.2. повертається що-небудь у строковому форматі подяка
ankush yadav

Схоже, що формат даних не працює для комірок Формули, він повертає рядкове представлення формули замість значення
gaurav5430

1
Лише одна незначна примітка: Будь ласка, надайте короткі фрагменти коду для таких відповідей, також якщо вони вказані у наданих посиланнях
BAERUS

@ gaurav5430 Так, це не добре поєднується з формулами ... За словами doc,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. Клас "Робоча книга" забезпечує оцінювач формул за допомогою 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 дуже ясно , що ви не повинні робити це так : Якщо то , що ви хочете зробити , це отримати строкове значення для цифрової камери, зупинка!. Це не спосіб зробити це. Натомість для отримання значення рядка числової чи булевої або датової комірки використовуйте замість DataFormatter.
Гаграварр

4

Спробуйте:

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

Чи слід правильно відформатувати номер.


Як я розумію, запитувач хоче вміти розрізняти 2і 2.0. Ваше рішення не зробить цього. (Але все ж, ласкаво просимо до Stack Overflow!)
Paŭlo Ebermann

1

Поки комірка знаходиться в текстовому форматі до того, як користувач набере номер, POI дозволить отримати значення у вигляді рядка. Одним із ключових моментів є те, що якщо у верхньому лівому куті комірки є невеликий зелений трикутник, який відформатований як Текст, ви зможете отримати його значення у вигляді рядка (зелений трикутник з’являється щоразу, коли щось, що видається числом примушується до текстового формату). Якщо у вас є клітини, відформатовані у тексті, які містять числа, але POI не дозволить отримувати ці значення як рядки, ви можете зробити кілька даних для даних електронної таблиці, щоб дозволити:

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

Останнє, що ви можете зробити, це те, що якщо ви використовуєте POI для отримання даних з електронної таблиці Excel 2007, ви можете використовувати метод "getRawValue ()" для класу Cell. Це не байдуже, який формат. Він просто поверне рядок із необробленими даними.


0

Коли ми читаємо числове значення комірки MS Excel за допомогою бібліотеки POI Apache, воно читає його як числове. Але колись ми хочемо, щоб він читався як рядок (наприклад, номери телефонів тощо). Ось як я це зробив:

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

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

  3. Додати ще один стовпець

  4. Виберіть повний стовпець, створений на кроці 1., та виберіть Правка-> КОПІЮВАННЯ

  5. Перейдіть до верхньої комірки стовпця, створеного на кроці 3. та виберіть Правка-> Спеціальна вставка

  6. У відкритому вікні виберіть перемикач "Значення"

  7. Виберіть "ОК"

  8. Тепер читайте, використовуючи API POI ... після читання на Java ... просто видаліть перший символ, тобто "!"


Здається, ваше рішення є непридатним, якщо ви самі не створюєте файли excel, чи не так? (Також ви могли б укласти відповідь у свою відповідь? Це не так довго.)
Pa --lo Ebermann

Так, його не можна використовувати, коли ви самі не виробляєте файл excel.
Асиф Шахзад

0

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

Рішення:

  • Зберігайте все форматування як загальне.
  • Тут я припускаю, що цифри зберігаються у колонці А, починаючи з рядка 1.
  • Поставте "у стовпчик" і скопіюйте стільки рядків, скільки потрібно. На робочому аркуші нічого не з’являється, але натискаючи на клітинку, ви можете побачити апостоф на панелі формул.
  • У стовпці C: = B1 і A1.
  • Виберіть усі клітинки у стовпці С та зробіть спеціальну вставку у стовпчик D за допомогою параметра Значення.

Привіт, престо, всі цифри, але зберігаються як Текст.


0

getStringCellValue повертає NumberFormatException, якщо тип комірки числовий. Якщо ви не хочете змінювати тип комірки на рядок, ви можете це зробити.

String rsdata = "";
try {
    rsdata = cell.getStringValue();
} catch (NumberFormatException ex) {
    rsdata = cell.getNumericValue() + "";
}

0

Багато з цих відповідей посилаються на стару документацію та класи POI. У найновішій POI 3.16 клітинка з типами int застаріла

Cell.CELL_TYPE_STRING

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

Натомість можна використовувати перелік CellType .

CellType.STRING 

Просто не забудьте оновити свою пам’ятність залежністю від poi, а також залежністю poi-ooxml до нової версії 3.16, інакше ви продовжуватимете винятки. Однією з переваг цієї версії є те, що ви можете вказати тип комірки під час створення комірки, усуваючи всі додаткові етапи, описані в попередніх відповідях:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);

0

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

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

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

Виноска: numericColumn - це int, який генерується при читанні заголовка обробленого файлу.


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

Я пробував це, і це працювало на мене


-1

Ви в будь-якому разі керуєте робочим аркушем excel? Чи є шаблон, який користувачі мають, щоб дати вам вклад? Якщо так, ви можете мати формат коду для вхідних комірок для вас.




-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 змінює лише спосіб відображення значення, але не змінює спосіб збереження значення, якщо воно не буде введене знову (наприклад, натисканням клавіші return, що знаходиться в комірці).

Незалежно від того, чи Excel правильно зберігає значення як текст, позначається маленьким зеленим трикутником, який Excel відображає у лівому верхньому куті комірки, якщо він вважає, що комірка містить число, але форматується як текст.


-3

киньте до int, тоді зробіть a .toString(). Це некрасиво, але це працює.


Проблема полягає в тому, що якщо в A2 є 2.0, мені потрібно отримати рядок "2.0", а якщо 2, то рядок "2".
joycollector
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.