Wie kann ich numerische Zeichenfolgen in Excel-Zellen als Zeichenfolge (nicht als Zahlen) lesen?

146
  1. Ich habe eine Excel-Datei mit solchen Inhalten:

    • A1: SomeString

    • A2: 2

    Alle Felder sind auf das String-Format eingestellt.

  2. Wenn ich die Datei in Java mit POI lese, wird angezeigt, dass A2 im numerischen Zellenformat vorliegt.

  3. Das Problem ist, dass der Wert in A2 2 oder 2,0 sein kann (und ich möchte sie unterscheiden können), also kann ich nicht einfach verwenden .toString().

Was kann ich tun, um den Wert als Zeichenfolge zu lesen?

Joycollector
quelle

Antworten:

319

Ich hatte das gleiche Problem. Ich habe dies cell.setCellType(Cell.CELL_TYPE_STRING);vor dem Lesen des Zeichenfolgenwerts getan , wodurch das Problem unabhängig davon gelöst wurde, wie der Benutzer die Zelle formatiert hat.

wil
quelle
Ich benutze poi-3.8-beta4 und es funktioniert wie erwartet! Warum akzeptiert TS dies nicht als Antwort?
Swdev
Beachten Sie, dass die POI-Konvertierung von numerisch in Zeichenfolge das Systemgebietsschema nicht berücksichtigt, sondern immer den Punkt als Dezimaltrennzeichen verwendet. Wenn Ihr System beispielsweise "," verwendet und in Excel-Zahlen wie "1,9" aussehen, gibt der POI stattdessen "1,9" zurück.
Alexey Berezkin
53
Beachten Sie, dass die Apache POI-Javadocs ausdrücklich sagen, dass Sie dies nicht tun sollen! Wie sie erklären, sollten Sie stattdessen
DataFormatter
6
Gagravarrs Warnung davor ist richtig! Aus den Dokumenten: "Wenn Sie einen String-Wert für Ihre numerische Zelle erhalten möchten, stoppen Sie!. Dies ist nicht die richtige Vorgehensweise. Verwenden Sie stattdessen zum Abrufen des String-Werts einer numerischen, booleschen oder Datumszelle Stattdessen DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Ich habe diese Technik selbst verwendet, bis ich versehentlich Daten geändert habe, die ich nicht ändern wollte. (Setzen Sie den Typ auf String, lesen Sie den Wert, setzen Sie den Typ zurück auf numerisch, lesen Sie erneut und erhalten Sie einen anderen numerischen Wert!)
Chris Finley
6
Verwenden Sie DataFormatter. Der Javadoc warnt uns davor, die oben beschriebene Methode anzuwenden.
Balu SKT
96

Ich glaube nicht, dass wir diese Klasse hatten, als Sie die Frage gestellt haben, aber heute gibt es eine einfache Antwort.

Sie möchten die DataFormatter-Klasse verwenden . Sie übergeben dieser Zelle eine Zelle, und es ist am besten, Ihnen eine Zeichenfolge zurückzugeben, die enthält, was Excel Ihnen für diese Zelle anzeigen würde. Wenn Sie eine Zeichenfolgenzelle übergeben, erhalten Sie die Zeichenfolge zurück. Wenn Sie eine numerische Zelle mit angewendeten Formatierungsregeln übergeben, wird die darauf basierende Zahl formatiert und die Zeichenfolge zurückgegeben.

Für Ihren Fall würde ich annehmen, dass auf die numerischen Zellen eine ganzzahlige Formatierungsregel angewendet wird. Wenn Sie DataFormatter bitten, diese Zellen zu formatieren, erhalten Sie eine Zeichenfolge mit der Ganzzahlzeichenfolge zurück.

Beachten Sie auch, dass viele Leute dies vorschlagen cell.setCellType(Cell.CELL_TYPE_STRING), aber die Apache POI JavaDocs geben ganz klar an, dass Sie dies nicht tun sollten ! Wenn Sie den setCellTypeAufruf ausführen, verliert die Formatierung, da die Javadocs erklären, dass die einzige Möglichkeit zum Konvertieren in einen String mit verbleibender Formatierung die Verwendung der DataFormatter-Klasse ist .

Gagravarr
quelle
Danke @Gagravarr, nur Ihre Antwort funktioniert für mich, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> konvertiert den Wert 2.2 als 2.2000000000000002, aber ich möchte 2.2. es gibt alles im String-Format zurück danke
ankush yadav
Datenformatierer scheinen nicht für Formelzellen zu funktionieren, sondern geben eine Zeichenfolgendarstellung der Formel anstelle des Werts zurück
gaurav5430
1
Nur eine kleine Anmerkung: Bitte geben Sie kurze Code-Schnipsel für solche Antworten an, auch wenn diese in den bereitgestellten Links angegeben sind
BAERUS
@ gaurav5430 Ja, es passt nicht gut zu Formeln ... Laut 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

Der folgende Code funktionierte für mich für jeden Zelltyp.

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
quelle
4
Hat gut funktioniert! Mein Vorschlag wäre, die Art und Weise zu ändern, in der der FormulaEvaluator abgerufen wird. Die Workbook-Klasse bietet über die getCreationHelper().createFormulaEvaluator()Methode einen Formelauswerter . Auf diese Weise wird Ihr Code nicht mit der HSSFFormulaEvaluator-Klasse gekoppelt.
Vitor Santos
Dies sollte die akzeptierte Antwort sein. Danke @ Vinayak
Phas1c
Kann FormulaEvaluatoreinfach aus dieser Lösung entfernt werden? Hat es einen Zweck?
P.Brian.Mackey
1
Der Aufruf von objFormulaEvaluator.evaluate ist nicht erforderlich. Der Rückgabewert davon wird hier nicht verwendet.
Radu Simionescu
32

Ich würde den folgenden Ansatz empfehlen, wenn das Ändern des Zelltyps unerwünscht ist:

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

NumberToTextConverter kann Doppelwerte mithilfe von Excel-Regeln ohne Genauigkeitsverlust korrekt in einen Text konvertieren.

Stanislav Mamontov
quelle
Wirklich spannender Rat! Danke dir! Es ermöglicht das Abrufen nicht konvertierter Werte im Gegensatz zum Setzen von cellType auf String.
Gleb Egunov
Ich erhalte 44007 als Ausgabe für den Zellenwert vom 25.06.2020. Was mache ich falsch?
Vinay
10

Ja, das funktioniert perfekt

empfohlen:

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

alt:

cell.setCellType(Cell.CELL_TYPE_STRING);

Selbst wenn Sie ein Problem beim Abrufen eines Werts aus celleiner Formel haben, funktioniert dies dennoch.

Rajesh Mbm
quelle
5
Bei doppelten Werten muss man jedoch vorsichtig sein. Für mich verwandelte es den Wert 7.9 in 7.8999956589965 ...
Chris
2
Die Apache POI-Javadocs sind sehr klar, dass Sie es nicht so machen sollten : Wenn Sie einen String-Wert für Ihre numerische Zelle erhalten möchten, hören Sie auf!. Dies ist nicht der richtige Weg. Verwenden Sie stattdessen DataFormatter, um den Zeichenfolgenwert einer numerischen, booleschen oder Datumszelle abzurufen.
Gagravarr
4

Versuchen:

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

Sollte die Nummer richtig formatieren.

ich nehme
quelle
Soweit ich weiß, möchte der Fragesteller zwischen 2und unterscheiden können 2.0. Ihre Lösung würde dies nicht tun. (Aber trotzdem willkommen bei Stack Overflow!)
Paŭlo Ebermann
1

Solange die Zelle im Textformat vorliegt, bevor der Benutzer die Nummer eingibt, können Sie den Wert über den POI als Zeichenfolge abrufen. Ein Schlüssel ist, dass Sie, wenn sich in der oberen linken Ecke der Zelle ein kleines grünes Dreieck befindet, das als Text formatiert ist, dessen Wert als Zeichenfolge abrufen können (das grüne Dreieck wird immer dann angezeigt, wenn es sich um eine Zahl handelt wird in ein Textformat gezwungen). Wenn Sie textformatierte Zellen haben, die Zahlen enthalten, der POI jedoch nicht zulässt, dass Sie diese Werte als Zeichenfolgen abrufen, können Sie einige Schritte mit den Tabellenkalkulationsdaten ausführen, um Folgendes zu ermöglichen:

  • Doppelklicken Sie auf die Zelle, damit sich der Bearbeitungscursor in der Zelle befindet, und klicken Sie dann auf die Eingabetaste (dies kann jeweils nur für eine Zelle erfolgen).
  • Verwenden Sie die Textkonvertierungsfunktion von Excel 2007 (die für mehrere Zellen gleichzeitig ausgeführt werden kann).
  • Schneiden Sie die fehlerhaften Werte an einer anderen Stelle aus, formatieren Sie die Tabellenzellen als Text neu und fügen Sie die zuvor ausgeschnittenen Werte als unformatierte Werte wieder in den richtigen Bereich ein.

Als letztes können Sie die Methode 'getRawValue ()' der Zellenklasse verwenden, wenn Sie POI verwenden, um Daten aus einer Excel 2007-Tabelle abzurufen. Es ist egal, wie das Format ist. Es wird einfach eine Zeichenfolge mit den Rohdaten zurückgegeben.

Mark Farnsworth
quelle
0

Wenn wir den numerischen Zellenwert von MS Excel mithilfe der Apache POI-Bibliothek lesen, wird er als numerisch gelesen. Aber manchmal möchten wir, dass es als Zeichenfolge gelesen wird (z. B. Telefonnummern usw.). So habe ich es gemacht:

  1. Fügen Sie eine neue Spalte mit der ersten Zelle = CONCATENATE ("!", D2) ein. Ich gehe davon aus, dass D2 die Zellen-ID Ihrer Telefonnummernspalte ist. Ziehen Sie die neue Zelle bis zum Ende.

  2. Wenn Sie nun die Zelle mit POI lesen, wird die Formel anstelle des berechneten Werts gelesen. Gehen Sie nun wie folgt vor:

  3. Fügen Sie eine weitere Spalte hinzu

  4. Wählen Sie die in Schritt 1 erstellte vollständige Spalte aus und wählen Sie Bearbeiten-> KOPIEREN

  5. Gehen Sie zur obersten Zelle der in Schritt 3 erstellten Spalte und wählen Sie Bearbeiten-> Inhalte einfügen

  6. Wählen Sie im geöffneten Fenster das Optionsfeld "Werte"

  7. Wählen Sie "OK"

  8. Lesen Sie jetzt mit der POI-API ... nach dem Lesen in Java ... entfernen Sie einfach das erste Zeichen, dh "!"

Asif Shahzad
quelle
Ihre Lösung scheint nicht verwendbar zu sein, wenn man die Excel-Dateien nicht selbst erstellt, oder? (Könnten Sie auch einen Auszug in Ihre Antwort einfügen? Es ist nicht so lange.)
Paŭlo Ebermann
Ja, es kann nicht verwendet werden, wenn man selbst keine Excel-Datei erstellt.
Asif Shahzad
0

Ich hatte auch ein ähnliches Problem mit einem Datensatz von Tausenden von Zahlen und ich denke, dass ich einen einfachen Weg gefunden habe, um es zu lösen. Ich musste den Apostroph vor einer Zahl einfügen, damit ein separater DB-Import die Zahlen immer als Text sieht. Zuvor wurde die Nummer 8 als 8.0 importiert.

Lösung:

  • Behalten Sie die gesamte Formatierung als Allgemein bei.
  • Hier gehe ich davon aus, dass Zahlen in Spalte A ab Zeile 1 gespeichert sind.
  • Fügen Sie das 'in Spalte B ein und kopieren Sie so viele Zeilen wie nötig. Im Arbeitsblatt wird nichts angezeigt. Wenn Sie jedoch auf die Zelle klicken, wird das Apostop in der Formelleiste angezeigt.
  • In Spalte C: = B1 & A1.
  • Wählen Sie alle Zellen in Spalte C aus und fügen Sie mit der Option Werte ein Special in Spalte D ein.

Hey Presto alle Zahlen aber als Text gespeichert.

Mark Holmes
quelle
0

getStringCellValue gibt NumberFormatException zurück, wenn der Zelltyp numerisch ist. Wenn Sie den Zelltyp nicht in Zeichenfolge ändern möchten, können Sie dies tun.

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

Viele dieser Antworten beziehen sich auf alte POI-Dokumentationen und -Klassen. Im neuesten POI 3.16 ist Cell mit den int-Typen veraltet

Cell.CELL_TYPE_STRING

Geben Sie hier die Bildbeschreibung ein

Stattdessen kann die CellType-Aufzählung verwendet werden.

CellType.STRING 

Aktualisieren Sie Ihren POM nur mit der Poi-Abhängigkeit sowie der Poi-Ooxml-Abhängigkeit auf die neue Version 3.16, da sonst weiterhin Ausnahmen auftreten. Ein Vorteil dieser Version besteht darin, dass Sie den Zelltyp zum Zeitpunkt der Erstellung der Zelle angeben können, wodurch alle in den vorherigen Antworten beschriebenen zusätzlichen Schritte entfallen:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);
Nelda.techspiress
quelle
0

Ich würde viel lieber den Weg der Antwort von Wil oder Vinayak Dornala gehen, leider haben sie meine Leistung viel zu sehr beeinflusst. Ich habe mich für eine HACKY- Lösung für implizites Casting entschieden:

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

Ich schlage nicht vor, dass Sie dies tun, da es in meiner Situation aufgrund der Funktionsweise des Systems funktioniert hat und ich eine zuverlässige Dateiquelle hatte.

Fußnote: numericColumn Ist ein int, das aus dem Lesen des Headers der verarbeiteten Datei generiert wird.

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

Ich habe es versucht und es hat bei mir funktioniert

Prasanna
quelle
-1

Kontrollieren Sie das Excel-Arbeitsblatt trotzdem? Gibt es eine Vorlage, über die die Benutzer Ihnen die Eingabe geben können? In diesem Fall können Sie die Eingabezellen für Sie im Codeformat formatieren.

datatoo
quelle
-1

Das hat perfekt für mich funktioniert.

Double legacyRow = row.getCell(col).getNumericCellValue();
String legacyRowStr = legacyRow.toString();
if(legacyRowStr.contains(".0")){
    legacyRowStr = legacyRowStr.substring(0, legacyRowStr.length()-2);
}
Rama Krishna
quelle
-2

Wir hatten das gleiche Problem und zwangen unsere Benutzer, die Zellen vor der Eingabe des Werts als "Text" zu formatieren . Auf diese Weise speichert Excel gerade Zahlen korrekt als Text. Wenn das Format danach geändert wird, ändert Excel nur die Art und Weise, wie der Wert angezeigt wird, aber nicht die Art und Weise, wie der Wert gespeichert wird, es sei denn, der Wert wird erneut eingegeben (z. B. durch Drücken der Eingabetaste in der Zelle).

Ob Excel den Wert korrekt als Text gespeichert hat oder nicht, wird durch das kleine grüne Dreieck angezeigt, das Excel in der linken oberen Ecke der Zelle anzeigt, wenn es glaubt, dass die Zelle eine Zahl enthält, aber als Text formatiert ist.

Turismo
quelle
-3

Wirke zu einem Int und mache dann einen .toString(). Es ist hässlich, aber es funktioniert.

WolfmanDragon
quelle
Das Problem ist, dass ich, wenn es 2.0 in A2 gibt, die Zeichenfolge "2.0" erhalten muss, und wenn 2, dann die Zeichenfolge "2".
Joycollector