Comment puis-je lire des chaînes numériques dans des cellules Excel sous forme de chaîne (et non de nombres)?

146
  1. J'ai un fichier Excel avec un tel contenu:

    • A1: SomeString

    • A2: 2

    Tous les champs sont définis au format chaîne.

  2. Lorsque je lis le fichier en java en utilisant POI, cela indique que A2 est au format de cellule numérique.

  3. Le problème est que la valeur dans A2 peut être 2 ou 2.0 (et je veux pouvoir les distinguer) donc je ne peux pas simplement utiliser .toString().

Que puis-je faire pour lire la valeur sous forme de chaîne?

joycollector
la source

Réponses:

319

J'ai eu le même problème. Je l'ai fait cell.setCellType(Cell.CELL_TYPE_STRING);avant de lire la valeur de la chaîne, ce qui a résolu le problème quelle que soit la façon dont l'utilisateur a formaté la cellule.

wil
la source
J'utilise poi-3.8-beta4, et ça marche comme prévu! Pourquoi TS n'accepte-t-il pas cela comme réponse?
swdev
Sachez que la conversion POI numérique en chaîne ne prend pas en compte les paramètres régionaux du système, elle utilise toujours le point comme séparateur décimal. Par exemple, si votre système utilise ",", et dans Excel les nombres ressemblent à "1,9", POI renverra "1.9" à la place.
Alexey Berezkin
53
Notez que les javadocs Apache POI disent explicitement de ne pas faire cela! Comme ils l'expliquent, vous devriez utiliser DataFormatter à la place
Gagravarr
6
L'avertissement de Gagravarr contre cela est juste! Dans la documentation: "Si vous voulez obtenir une valeur de chaîne pour votre cellule numérique, arrêtez !. Ce n'est pas la façon de le faire. Au lieu de cela, pour récupérer la valeur de chaîne d'une cellule numérique, booléenne ou de date, utilisez DataFormatter à la place. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/ ... J'utilisais moi-même cette technique jusqu'à ce que je finisse par changer accidentellement des données que je n'avais pas l'intention de changer. (Définissez le type sur String, lisez la valeur, redéfinissez le type sur numérique, relisez et obtenez une valeur numérique différente!)
Chris Finley
6
Utilisez DataFormatter. Le Javadoc nous met en garde contre l'utilisation de la méthode ci-dessus.
Balu SKT
96

Je ne pense pas que nous ayons eu ce cours lorsque vous avez posé la question, mais aujourd'hui, il y a une réponse facile.

Ce que vous voulez faire, c'est utiliser la classe DataFormatter . Vous passez cette cellule et il fait de son mieux pour vous renvoyer une chaîne contenant ce qu'Excel vous montrerait pour cette cellule. Si vous lui passez une cellule de chaîne, vous récupérerez la chaîne. Si vous lui passez une cellule numérique avec des règles de mise en forme appliquées, il formatera le nombre en fonction de celles-ci et vous rendra la chaîne.

Pour votre cas, je suppose que les cellules numériques ont une règle de mise en forme entière qui leur est appliquée. Si vous demandez à DataFormatter de formater ces cellules, il vous rendra une chaîne contenant la chaîne entière.

Notez également que beaucoup de gens suggèrent de le faire cell.setCellType(Cell.CELL_TYPE_STRING), mais les JavaDocs Apache POI indiquent clairement que vous ne devriez pas faire cela ! Faire cet setCellTypeappel perdra la mise en forme, car les javadocs expliquent que la seule façon de convertir en une chaîne avec le formatage restant est d'utiliser la classe DataFormatter .

Gagravarr
la source
Merci @Gagravarr, seule votre réponse fonctionne pour moi, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> pour convertir la valeur 2.2 en 2.2000000000000002, mais je veux 2.2. il retourne quoi que ce soit au format chaîne merci
ankush yadav
dataformatter ne semble pas fonctionner pour les cellules de formule, il renvoie une représentation sous forme de chaîne de la formule au lieu de la valeur
gaurav5430
1
Juste une remarque mineure: veuillez fournir des extraits de code courts pour ces réponses, même si ceux-ci sont indiqués dans les liens fournis
BAERUS
@ gaurav5430 Oui, cela ne va pas bien avec les formules ... Selon le 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

Le code ci-dessous a fonctionné pour moi pour tout type de cellule.

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
la source
4
A bien fonctionné! Ma suggestion serait de changer la façon dont le FormulaEvaluator est récupéré. La classe Workbook fournit un évaluateur de formule via la getCreationHelper().createFormulaEvaluator()méthode. De cette façon, votre code ne sera pas couplé à la classe HSSFFormulaEvaluator.
Vitor Santos
Cela devrait être la réponse acceptée. Merci @Vinayak
Phas1c
Peut-on FormulaEvaluatorsimplement être retiré de cette solution? Cela sert-il un but?
P.Brian.Mackey
1
l'appel à objFormulaEvaluator.evaluate n'est pas nécessaire. La valeur de retour de qui n'est pas utilisée ici.
Radu Simionescu
32

Je recommanderais l'approche suivante lorsque la modification du type de cellule n'est pas souhaitable:

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

NumberToTextConverter peut convertir correctement une valeur double en texte en utilisant les règles d'Excel sans perte de précision.

Stanislav Mamontov
la source
Un conseil vraiment excitant! Je vous remercie! Il permet d'obtenir des valeurs non converties contrairement à la définition de cellType sur String.
Gleb Egunov
J'obtiens 44007 en sortie pour la valeur de cellule du 25/06/2020. Qu'est-ce que je fais mal?
Vinay
10

Oui, cela fonctionne parfaitement

conseillé:

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

vieux:

cell.setCellType(Cell.CELL_TYPE_STRING);

même si vous avez un problème avec la récupération d'une valeur à partir d' cellune formule, cela fonctionne toujours.

Rajesh Mbm
la source
5
Mais vous devez être prudent en utilisant ceci pour des valeurs doubles. Pour moi, il a transformé la valeur 7,9 en 7,8999956589965 ...
Chris
2
Les javadocs Apache POI sont très clairs sur le fait que vous ne devriez pas le faire comme ça : si vous voulez obtenir une valeur String pour votre cellule numérique, arrêtez !. Ce n’est pas la façon de procéder. Au lieu de cela, pour récupérer la valeur de chaîne d'une cellule numérique, booléenne ou de date, utilisez plutôt DataFormatter.
Gagravarr
4

Essayer:

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

Doit formater le nombre correctement.

Je prends
la source
Si je comprends bien, le demandeur veut pouvoir faire la distinction entre 2et 2.0. Votre solution ne ferait pas cela. (Mais
quand
1

Tant que la cellule est au format texte avant que l'utilisateur ne saisisse le nombre, POI vous permettra d'obtenir la valeur sous forme de chaîne. Une clé est que s'il y a un petit triangle vert dans le coin supérieur gauche de la cellule qui est formaté comme Texte, vous pourrez récupérer sa valeur sous forme de chaîne (le triangle vert apparaît chaque fois que quelque chose qui semble être un nombre est contraint dans un format texte). Si vous avez des cellules au format texte qui contiennent des nombres, mais que POI ne vous permettra pas de récupérer ces valeurs sous forme de chaînes, vous pouvez effectuer certaines opérations sur les données de la feuille de calcul pour le permettre:

  • Double-cliquez sur la cellule pour que le curseur d'édition soit présent à l'intérieur de la cellule, puis cliquez sur Entrée (ce qui ne peut être fait qu'une cellule à la fois).
  • Utilisez la fonction de conversion de texte Excel 2007 (qui peut être effectuée sur plusieurs cellules à la fois).
  • Découpez les valeurs incriminées à un autre emplacement, reformatez les cellules de la feuille de calcul sous forme de texte, puis recollez les valeurs précédemment découpées en tant que valeurs non formatées dans la zone appropriée.

Une dernière chose que vous pouvez faire est que si vous utilisez POI pour obtenir des données à partir d'une feuille de calcul Excel 2007, vous pouvez utiliser la méthode 'getRawValue ()' de la classe Cell. Cela ne se soucie pas du format. Il renverra simplement une chaîne avec les données brutes.

Mark Farnsworth
la source
0

Lorsque nous lisons la valeur de la cellule numérique de MS Excel à l'aide de la bibliothèque Apache POI, il la lit comme numérique. Mais parfois, nous voulons qu'il soit lu sous forme de chaîne (par exemple, numéros de téléphone, etc.). Voici comment je l'ai fait:

  1. Insérez une nouvelle colonne avec la première cellule = CONCATENER ("!", D2). Je suppose que D2 est l'identifiant de votre colonne de numéro de téléphone. Faites glisser la nouvelle cellule jusqu'à la fin.

  2. Maintenant, si vous lisez la cellule en utilisant POI, il lira la formule au lieu de la valeur calculée. Maintenant, procédez comme suit:

  3. Ajouter une autre colonne

  4. Sélectionnez la colonne complète créée à l'étape 1. et choisissez Edition-> COPIER

  5. Accédez à la cellule supérieure de la colonne créée à l'étape 3. et sélectionnez Edition-> Collage spécial

  6. Dans la fenêtre ouverte, sélectionnez le bouton radio "Valeurs"

  7. Sélectionnez "OK"

  8. Maintenant, lisez en utilisant l'API POI ... après avoir lu en Java ... supprimez simplement le premier caractère, c'est-à-dire "!"

Asif Shahzad
la source
Votre solution ne semble pas utilisable si l'on ne produit pas soi-même les fichiers Excel, n'est-ce pas? (Aussi, pourriez-vous mettre un extrait dans votre réponse? Ce n'est pas si long.)
Paŭlo Ebermann
Oui, il ne peut pas être utilisé lorsque l'on ne produit pas soi-même de fichier Excel.
Asif Shahzad
0

J'ai également eu un problème similaire sur un ensemble de données de milliers de chiffres et je pense avoir trouvé un moyen simple de le résoudre. J'avais besoin d'insérer l'apostrophe avant un nombre afin qu'une importation DB distincte voie toujours les nombres sous forme de texte. Avant cela, le numéro 8 était importé en tant que 8.0.

Solution:

  • Gardez tout le formatage comme général.
  • Ici, je suppose que les nombres sont stockés dans la colonne A à partir de la ligne 1.
  • Mettez dans la colonne B et copiez autant de lignes que nécessaire. Rien n'apparaît dans la feuille de calcul mais en cliquant sur la cellule, vous pouvez voir l'apostophe dans la barre de formule.
  • Dans la colonne C: = B1 & A1.
  • Sélectionnez toutes les cellules de la colonne C et effectuez un collage spécial dans la colonne D à l'aide de l'option Valeurs.

Hey Presto tous les numéros mais stockés sous forme de texte.

Mark Holmes
la source
0

getStringCellValue renvoie NumberFormatException si le type de cellule est numérique. Si vous ne souhaitez pas changer le type de cellule en chaîne, vous pouvez le faire.

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

Beaucoup de ces réponses font référence à de vieilles documentations et classes de POI. Dans le dernier POI 3.16, la cellule avec les types int est obsolète

Cell.CELL_TYPE_STRING

entrez la description de l'image ici

Au lieu de cela, l' énumération CellType peut être utilisée.

CellType.STRING 

Assurez-vous simplement de mettre à jour votre pom avec la dépendance poi ainsi que la dépendance poi-ooxml vers la nouvelle version 3.16, sinon vous continuerez à obtenir des exceptions. L'un des avantages de cette version est que vous pouvez spécifier le type de cellule au moment de la création de la cellule en éliminant toutes les étapes supplémentaires décrites dans les réponses précédentes:

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

Je préférerais de loin suivre la voie de la réponse de Wil ou Vinayak Dornala, malheureusement ils ont beaucoup trop affecté ma performance. J'ai opté pour une solution HACKY de casting implicite:

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

Je ne vous suggère pas de faire cela, pour ma situation, cela a fonctionné en raison de la nature du fonctionnement du système et j'avais une source de fichiers fiable.

Note de bas de page: numericColumn Est un int qui est généré à partir de la lecture de l'en-tête du fichier traité.

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

J'ai essayé ça et ça a marché pour moi

Prasanna
la source
-1

Contrôlez-vous la feuille de calcul Excel de toute façon? Les utilisateurs disposent-ils d'un modèle pour vous donner leur avis? Si tel est le cas, vous pouvez mettre en forme le code des cellules d'entrée pour vous.

datatoo
la source
-1

Cela a fonctionné parfaitement pour moi.

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

Nous avons eu le même problème et avons obligé nos utilisateurs à formater les cellules en tant que «texte» avant d' entrer la valeur. De cette façon, Excel stocke correctement les nombres pairs sous forme de texte. Si le format est modifié par la suite, Excel ne modifie que la façon dont la valeur est affichée mais ne change pas la façon dont la valeur est stockée à moins que la valeur ne soit saisie à nouveau (par exemple en appuyant sur Entrée dans la cellule).

Le fait qu'Excel ait correctement stocké la valeur sous forme de texte est indiqué par le petit triangle vert qu'Excel affiche dans le coin supérieur gauche de la cellule s'il pense que la cellule contient un nombre mais est formatée sous forme de texte.

Tourisme
la source
-3

transtyper en un int puis faire un .toString(). C'est moche mais ça marche.

Homme-loupDragon
la source
Le problème est que s'il y a 2.0 dans A2, je dois obtenir la chaîne "2.0", et si 2, alors la chaîne "2".
joycollector