Jak odczytać ciągi liczbowe w komórkach programu Excel jako ciąg (nie liczby)?

146
  1. Mam plik excela z taką zawartością:

    • A1: SomeString

    • A2: 2

    Wszystkie pola są ustawione na format ciągów.

  2. Kiedy czytam plik w java za pomocą POI, mówi, że A2 jest w formacie komórki numerycznej.

  3. Problem polega na tym, że wartość w A2 może wynosić 2 lub 2,0 (i chcę móc je rozróżnić), więc nie mogę po prostu użyć .toString().

Co mogę zrobić, aby odczytać wartość jako ciąg znaków?

joycollector
źródło

Odpowiedzi:

319

Miałem ten sam problem. Zrobiłem cell.setCellType(Cell.CELL_TYPE_STRING);przed odczytaniem wartości ciągu, co rozwiązało problem niezależnie od tego, jak użytkownik sformatował komórkę.

wil
źródło
Używam poi-3.8-beta4 i działa zgodnie z oczekiwaniami! Dlaczego TS nie przyjmuje tego jako odpowiedzi?
swdev,
Należy pamiętać, że konwersja liczb POI na ciąg nie bierze pod uwagę ustawień regionalnych systemu, zawsze używa kropki jako separatora dziesiętnego. Na przykład, jeśli Twój system używa „,”, aw programie Excel liczby wyglądają jak „1,9”, POI zwróci zamiast tego „1,9”.
Alexey Berezkin
53
Zauważ, że javadocs Apache POI wyraźnie mówi, aby tego nie robić! Jak wyjaśniają, powinieneś zamiast tego użyć DataFormatter
Gagravarr
6
Ostrzeżenie Gagravarra przed takim postępowaniem jest słuszne! Z dokumentacji: „Jeśli chcesz uzyskać wartość ciągu dla swojej komórki numerycznej, zatrzymaj się !. To nie jest sposób na zrobienie tego. Zamiast tego, aby pobrać wartość ciągu z komórki numerycznej, logicznej lub daty, użyj Zamiast tego DataFormatter ”. poi.apache.org/apidocs/org/apache/poi/ss/usermodel/... Sam używałem tej techniki, dopóki przypadkowo nie zmieniłem danych, których nie zamierzałem zmieniać. (Ustaw typ na String, odczytaj wartość, ustaw typ z powrotem na numeryczny, przeczytaj ponownie i uzyskaj inną wartość liczbową!)
Chris Finley
6
Użyj DataFormatter. Javadoc ostrzega nas przed użyciem powyższej metody.
Balu SKT
96

Nie sądzę, żebyśmy mieli tę klasę, kiedy zadałeś pytanie, ale dzisiaj jest prosta odpowiedź.

To, co chcesz zrobić, to użyć klasy DataFormatter . Przekazujesz tę komórkę i robi wszystko, co w jej mocy, aby zwrócić ci ciąg zawierający to, co Excel pokaże ci dla tej komórki. Jeśli przekażesz mu komórkę łańcuchową, otrzymasz ciąg z powrotem. Jeśli przekażesz mu komórkę numeryczną z zastosowanymi regułami formatowania, sformatuje liczbę na ich podstawie i zwróci ci ciąg.

W twoim przypadku założyłbym, że komórki numeryczne mają zastosowaną regułę formatowania liczb całkowitych. Jeśli poprosisz DataFormatter o sformatowanie tych komórek, zwróci ci ciąg zawierający ciąg będący liczbą całkowitą.

Należy również zauważyć, że wiele osób sugeruje to zrobić cell.setCellType(Cell.CELL_TYPE_STRING), ale Apache POI JavaDocs dość wyraźnie stwierdza, że ​​nie należy tego robić ! Wykonanie setCellTypewywołania spowoduje utratę formatowania, ponieważ javadocs wyjaśniają, że jedynym sposobem konwersji na łańcuch z pozostałym formatowaniem jest użycie klasy DataFormatter .

Gagravarr
źródło
Dzięki @Gagravarr, tylko twoja odpowiedź działa dla mnie, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> w konwersji wartości 2.2 na 2.2000000000000002, ale chcę 2.2. zwraca wszystko w formacie string dzięki
ankush yadav
dataformatter wydaje się nie działać dla komórek Formuły, zwraca ciąg znaków reprezentujący formułę zamiast wartości
gaurav5430
1
Tylko jedna drobna uwaga: proszę podać krótkie fragmenty kodu dla takich odpowiedzi, również jeśli są one określone w podanych linkach
BAERUS
@ gaurav5430 Tak, nie pasuje do formuł ... Według 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

Poniższy kod działał dla mnie dla każdego typu komórki.

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

}
Vinayak Dornala
źródło
4
Działało dobrze! Moją sugestią byłaby zmiana sposobu pobierania FormulaEvaluator. Klasa Workbook zapewnia ewaluator formuł za pośrednictwem getCreationHelper().createFormulaEvaluator()metody. W ten sposób Twój kod nie zostanie połączony z klasą HSSFFormulaEvaluator.
Vitor Santos
To powinna być akceptowana odpowiedź. Dzięki @Vinayak
Phas1c
Czy można go FormulaEvaluatorpo prostu usunąć z tego rozwiązania? Czy to służy celowi?
P.Brian. Mackey
1
wywołanie objFormulaEvaluator.evaluate nie jest konieczne. Zwracana wartość tego nie jest tutaj używana.
Radu Simionescu
32

Poleciłbym następujące podejście, gdy modyfikowanie typu komórki jest niepożądane:

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

NumberToTextConverter może poprawnie konwertować podwójną wartość na tekst przy użyciu reguł programu Excel bez utraty precyzji.

Stanislav Mamontov
źródło
Naprawdę ekscytująca rada! Dziękuję Ci! Umożliwia uzyskanie nieprzekonwertowanych wartości w przeciwieństwie do ustawienia cellType na String.
Gleb Egunov
Otrzymuję 44007 jako dane wyjściowe dla wartości komórki 25/06/2020. Co ja robię źle?
Vinay
10

Tak, to działa doskonale

Zalecana:

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

stary:

cell.setCellType(Cell.CELL_TYPE_STRING);

nawet jeśli masz problem z odzyskaniem wartości z cellformuły, to nadal działa.

Rajesh Mbm
źródło
5
Ale musisz uważać, używając tego dla podwójnych wartości. Dla mnie zmieniło to wartość 7,9 na 7,8999956589965 ...
Chris,
2
W Javadocs Apache POI są bardzo jasne, że nie powinno się robić to tak : Jeśli to, co chcesz zrobić, to wartość String na swojej komórce numerycznej, przystanek !. To nie jest sposób na zrobienie tego. Zamiast tego, aby pobrać wartość ciągu z komórki numerycznej, logicznej lub daty, użyj zamiast tego DataFormatter.
Gagravarr
4

Próbować:

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

Powinien poprawnie sformatować numer.

biorę
źródło
Jak rozumiem, pytający chce być w stanie odróżnić 2i 2.0. Twoje rozwiązanie by tego nie zrobiło. (Ale nadal witamy w Stack Overflow!)
Paŭlo Ebermann
1

Tak długo, jak komórka jest w formacie tekstowym, zanim użytkownik wpisze liczbę, POI pozwoli Ci uzyskać wartość w postaci ciągu. Jednym kluczem jest to, że jeśli w lewym górnym rogu komórki znajduje się mały zielony trójkąt sformatowany jako tekst, będziesz mógł pobrać jego wartość jako ciąg (zielony trójkąt pojawia się za każdym razem, gdy coś wygląda na liczbę jest wymuszona na format tekstowy). Jeśli masz komórki sformatowane jako tekst, które zawierają liczby, ale POI nie pozwalają na pobranie tych wartości w postaci ciągów, jest kilka rzeczy, które możesz zrobić z danymi arkusza kalkulacyjnego, aby to umożliwić:

  • Kliknij dwukrotnie komórkę, aby kursor edycji znajdował się w komórce, a następnie kliknij Enter (co można zrobić tylko w jednej komórce na raz).
  • Użyj funkcji konwersji tekstu programu Excel 2007 (co można zrobić na wielu komórkach jednocześnie).
  • Wytnij niewłaściwe wartości w innym miejscu, sformatuj ponownie komórki arkusza kalkulacyjnego jako tekst, a następnie wklej wcześniej wycięte wartości jako wartości niesformatowane z powrotem do odpowiedniego obszaru.

Ostatnią rzeczą, którą możesz zrobić, jest to, że jeśli używasz POI do uzyskiwania danych z arkusza kalkulacyjnego Excel 2007, możesz użyć metody klasy Cell „getRawValue ()”. To nie obchodzi, jaki jest format. Zwróci po prostu ciąg z surowymi danymi.

Mark Farnsworth
źródło
0

Kiedy odczytujemy wartość numeryczną komórki MS Excel za pomocą biblioteki Apache POI, odczytujemy ją jako liczbową. Ale czasami chcemy, aby był odczytywany jako ciąg (np. Numery telefonów itp.). Oto jak to zrobiłem:

  1. Wstaw nową kolumnę z pierwszą komórką = CONCATENATE („!”, D2). Zakładam, że D2 to identyfikator komórki w kolumnie z numerem telefonu. Przeciągnij nową komórkę do końca.

  2. Teraz, jeśli czytasz komórkę za pomocą POI, odczyta ona formułę zamiast obliczonej wartości. Teraz wykonaj następujące czynności:

  3. Dodaj kolejną kolumnę

  4. Zaznacz całą kolumnę utworzoną w kroku 1. i wybierz Edycja-> KOPIUJ

  5. Przejdź do górnej komórki kolumny utworzonej w kroku 3. i wybierz Edycja-> Wklej specjalnie

  6. W otwartym oknie wybierz przycisk opcji „Wartości”

  7. Wybierz „OK”

  8. Teraz czytaj za pomocą POI API… po przeczytaniu w Javie… po prostu usuń pierwszy znak, np. „!”

Asif Shahzad
źródło
Twoje rozwiązanie wydaje się nie nadawać się do użytku, jeśli ktoś nie tworzy samodzielnie plików Excela, prawda? (Czy mógłbyś
dołączyć
Tak, nie można go używać, gdy samemu nie tworzy się pliku Excel.
Asif Shahzad
0

Miałem też podobny problem ze zbiorem danych składającym się z tysięcy liczb i myślę, że znalazłem prosty sposób na rozwiązanie. Musiałem wstawić apostrof przed liczbą, aby oddzielny import DB zawsze widział liczby jako tekst. Wcześniej liczba 8 byłaby importowana jako 8.0.

Rozwiązanie:

  • Zachowaj całe formatowanie jako Ogólne.
  • Tutaj zakładam, że liczby są przechowywane w kolumnie A, zaczynając od wiersza 1.
  • Wstaw „w kolumnie B” i skopiuj tyle wierszy, ile potrzeba. Nic nie pojawia się w arkuszu, ale po kliknięciu komórki możesz zobaczyć apostof na pasku formuły.
  • W kolumnie C: = B1 i A1.
  • Wybierz wszystkie komórki w kolumnie C i wykonaj polecenie Wklej specjalnie do kolumny D za pomocą opcji Wartości.

Hej Presto wszystkie liczby, ale zapisane jako tekst.

Mark Holmes
źródło
0

getStringCellValue zwraca NumberFormatException, jeśli typ komórki jest numeryczny. Jeśli nie chcesz zmieniać typu komórki na ciąg, możesz to zrobić.

String rsdata = "";
try {
    rsdata = cell.getStringValue();
} catch (NumberFormatException ex) {
    rsdata = cell.getNumericValue() + "";
}
zawhtut
źródło
0

Wiele z tych odpowiedzi odnosi się do starej dokumentacji i klas POI. W najnowszym POI 3.16 komórka z typami int została wycofana

Cell.CELL_TYPE_STRING

wprowadź opis obrazu tutaj

Zamiast tego można użyć wyliczenia CellType .

CellType.STRING 

Po prostu upewnij się, że zaktualizowałeś swój pom za pomocą zależności poi, a także zależności poi-ooxml do nowej wersji 3.16, w przeciwnym razie nadal będziesz otrzymywać wyjątki. Jedną z zalet tej wersji jest to, że możesz określić typ komórki w momencie tworzenia komórki, eliminując wszystkie dodatkowe kroki opisane w poprzednich odpowiedziach:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);
Nelda.techspiress
źródło
0

Wolałbym raczej pójść drogą odpowiedzi wil lub Vinayak Dornala, niestety za bardzo wpłynęli na mój występ. Poszedłem na rozwiązanie HACKY niejawnego rzutowania:

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

Nie radzę tego robić, ponieważ w mojej sytuacji zadziałało ze względu na charakter działania systemu i miałem niezawodne źródło plików.

Przypis: numericColumn Jest liczbą int, która jest generowana na podstawie odczytu nagłówka przetwarzanego pliku.

KeaganFouche
źródło
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());
        }

Próbowałem tego i zadziałało dla mnie

Prasanna
źródło
-1

Czy w ogóle kontrolujesz arkusz programu Excel? Czy istnieje szablon, który użytkownicy mają do wprowadzania danych? Jeśli tak, możesz mieć formatowanie kodu dla komórek wejściowych.

datatoo
źródło
-1

To zadziałało idealnie dla mnie.

Double legacyRow = row.getCell(col).getNumericCellValue();
String legacyRowStr = legacyRow.toString();
if(legacyRowStr.contains(".0")){
    legacyRowStr = legacyRowStr.substring(0, legacyRowStr.length()-2);
}
Rama Krishna
źródło
-2

Mieliśmy ten sam problem i zmusiliśmy naszych użytkowników do sformatowania komórek jako „tekst” przed wprowadzeniem wartości. W ten sposób program Excel poprawnie przechowuje liczby parzyste jako tekst. Jeśli format zostanie później zmieniony, program Excel zmieni tylko sposób wyświetlania wartości, ale nie zmieni sposobu przechowywania wartości, chyba że wartość zostanie wprowadzona ponownie (np. Naciskając klawisz Return w komórce).

To, czy program Excel poprawnie zapisał wartość jako tekst, jest wskazywane przez mały zielony trójkąt, który program Excel wyświetla w lewym górnym rogu komórki, jeśli uważa, że ​​komórka zawiera liczbę, ale jest sformatowana jako tekst.

Turismo
źródło
-3

rzut na int, a następnie wykonaj .toString(). Jest brzydki, ale działa.

WolfmanDragon
źródło
Problem polega na tym, że jeśli w A2 jest 2.0, to muszę otrzymać ciąg „2.0”, a jeśli 2, to ciąg „2”.
joycollector