2017-10-19 20 views
0

Je dois lire les numéros de téléphone téléchargés via xls/xlsx dans une variable Java String, aussi près que possible de ce qui est affiché dans le fichier Excel.Apache POI impossible de détecter le format haché

J'ai donc ces données remplis: enter image description here

Comme vous pouvez le voir, la valeur réelle au sein de la cellule est 166609647, et son format avec 60#############, alors à la fin, nous voyons 60166609647 apparaissant sur la cellule. Je voudrais capturer le contenu de la cellule comme 60166609647 dans la chaîne mais jusqu'à présent, je réussis seulement à capturer 166609647, quelqu'un peut-il m'éclairer ce qui ne va pas?

Note: Si je change le format 60############-60000000000, je peux saisir 60166609647 sans aucun problème, mais le excel est téléchargé via le site public donc je ne peux pas respecter cela.

Le code est aussi simple que:

Cell cell = getTheCell(); // Got this after reading the sheets and rows 
DataFormatter df = new DataFormatter(); 
String value = df.formatCellValue(cell); 
// Here in value 
// If format is 600000000, I can get 60166609647 (right) 
// If format is 60#######, I get 166609647 (wrong) 

Bibliothèques J'utilise:

  • poi poi) (3.17
  • poi (poi-OOXML) 3.17
  • poi (poi-ooxml-schemas) 3.17
  • Java 7

Quelqu'un sait ce que je dois faire pour être en mesure de faire les choses correctement?

Merci.

+0

comme un bug d'Apache POI pour moi. Y a-t-il une chance que vous ayez pu écrire un test d'unité de junit montrant le problème, puis ouvrir un bug dans le bugzilla Apache POI? – Gagravarr

+0

@Gagravarr J'ai effectivement soumis une demande ici à https://bz.apache.org/bugzilla/show_bug.cgi?id=61638, y a-t-il quelque chose que j'ai besoin de modifier? –

Répondre

1

Le problème est multidimensionnel.

Dans un premier temps, le format numérique 60############ ne peut pas être appliqué en utilisant Java. Il conduit à java.lang.IllegalArgumentException: Malformed pattern "60############" en utilisant DecimalFormat.

Mais si le besoin est d'avoir chaque numéro préfixé par « 60 », puis les Excel formats numériques \6\0# ou "60"# devraient être possibles et doivent être traduits dans le modèle DecimalFormat'60'#. Mais apache poiDataFormatter ne supprime pas simplement toutes les citations des chaînes de format Excel, ce qui conduit à 60# qui est également un motif mal formé.

Le problème est dans DataFormatter.java:671ff.

J'ai patché dans mon MyDataFormatter comme ceci:

... 
     // Now, handle the other aspects like 
     // quoting and scientific notation 
     for(int i = 0; i < sb.length(); i++) { 
      char c = sb.charAt(i); 
/* 
      // remove quotes and back slashes 
      if (c == '\\' || c == '"') { 
       sb.deleteCharAt(i); 
       i--; 
*/ 
      // handle quotes and back slashes 
      if (c == '\\') { 
       sb.setCharAt(i, '\''); 
       sb.insert(i+2, '\''); 
       i+=2; 
      } else if (c == '"') { 
       sb.setCharAt(i, '\''); 
      // for scientific/engineering notation 
      } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') { 
       sb.deleteCharAt(i); 
       i--; 
      } 
     } 

     formatStr = sb.toString(); 
     formatStr = formatStr.replace("''", ""); 
     return formatStr; 
    } 
... 

En utilisant ce dans cet exemple:

import org.apache.poi.ss.usermodel.*; 
import org.apache.poi.ss.util.*; 

import java.io.FileInputStream; 

import java.lang.reflect.Method; 

class ExcelDataformatterExample { 

public static void main(String[] args) throws Exception { 

    Workbook wb = WorkbookFactory.create(new FileInputStream("ExcelExample.xlsx")); 

    DataFormatter df = new DataFormatter(); 
    MyDataFormatter mydf = new MyDataFormatter(); 

    Sheet sheet = wb.getSheetAt(0); 
    for (Row row : sheet) { 
    for (Cell cell : row) { 
    if (cell.getCellTypeEnum() == CellType.NUMERIC) { 
    CellReference cellRef = new CellReference(row.getRowNum(), cell.getColumnIndex()); 
    System.out.println("Cell " + cellRef.formatAsString()); 

    System.out.print("Excel's data format string: "); 
    String formatStr = cell.getCellStyle().getDataFormatString(); 
    System.out.println(formatStr); 

    System.out.print("Value using poi's data formatter: "); 
    Method cleanFormatForNumber = DataFormatter.class.getDeclaredMethod("cleanFormatForNumber", String.class); 
    cleanFormatForNumber.setAccessible(true); 
    String cleanFormatStr = (String)cleanFormatForNumber.invoke(df, formatStr); 
    System.out.print("using poi's cleanFormatStr: "); 
    System.out.print(cleanFormatStr + " result: "); 
    String value = df.formatCellValue(cell); 
    System.out.println(value); 

    System.out.print("Value using my data formatter: "); 
    cleanFormatForNumber = MyDataFormatter.class.getDeclaredMethod("cleanFormatForNumber", String.class); 
    cleanFormatForNumber.setAccessible(true); 
    cleanFormatStr = (String)cleanFormatForNumber.invoke(mydf, formatStr); 
    System.out.print("using my cleanFormatStr: "); 
    System.out.print(cleanFormatStr + " result: "); 
    value = mydf.formatCellValue(cell); 
    System.out.println(value); 

    } 
    } 
    } 
    wb.close(); 

} 

} 

Elle conduit à la sortie suivante, si les valeurs sont dans les cellules A1 à A4 formaté en Excel comme indiqué:

Cell A1 
Excel's data format string: \60########## 
Value using poi's data formatter: using poi's cleanFormatStr: 60########## result: 166609647 
Value using my data formatter: using my cleanFormatStr: '6'0########## result: 166609647 
Cell A2 
Excel's data format string: \60000000000 
Value using poi's data formatter: using poi's cleanFormatStr: 60000000000 result: 60166609647 
Value using my data formatter: using my cleanFormatStr: '6'0000000000 result: 60166609647 
Cell A3 
Excel's data format string: "60"# 
Value using poi's data formatter: using poi's cleanFormatStr: 60# result: 166609647 
Value using my data formatter: using my cleanFormatStr: '60'# result: 60166609647 
Cell A4 
Excel's data format string: \6\0# 
Value using poi's data formatter: using poi's cleanFormatStr: 60# result: 166609647 
Value using my data formatter: using my cleanFormatStr: '60'# result: 60166609647 
+0

Merci beaucoup pour les efforts déployés pour résoudre ce problème. J'essaie de digérer les codes, mais d'après les résultats, êtes-vous en train de dire que ce n'est pas une tâche facile de supporter globalement des formats comme "60 ####"? Les bonnes nouvelles sont que je n'ai pas besoin de détecter les décimales et beaucoup d'autres formats compliqués, donc si je peux invoquer les méthodes de format comme ce que vous avez fait, je pense que je peux simplement dupliquer les fonctions et remplacer # 'à' 0 ', pour obtenir ce que je veux finalement? –

+0

@Chor Wai Chun: Comme indiqué, le format numérique '60 ####' ne peut pas être appliqué en utilisant 'DecimalFormat' de Java. Mais c'est aussi sans signification pour moi. Préfixez tous les numéros avec "6" et mettez en plus un 0 avant les numéros jusqu'à 4 chiffres. Qu'est-ce que cela veut dire? Les formats 'Excel' '" 60 "#' ou '\ 6 \ 0 #' qui sont: préfixer tous les nombres avec "60" sont possibles en utilisant mon patch décrit. –

+0

est réellement sans signification pour le reste du monde haha, sauf en Malaisie où notre code de pays est 60, d'où nous l'ajouterons au début de notre numéro pour obtenir le format international. Je ne peux pas contrôler le type de format que mes utilisateurs appliqueraient, ce que je peux faire est d'ajouter le plus de soutien possible à leur entrée prédite. Donc je suppose que remplacer le '#' dans leur format à '0' avant d'appeler la fonction format est le meilleur pari que j'ai. –