2017-10-19 129 views
0

我需要將通過xls/xlsx上傳的電話號碼讀取到Java String變量中,儘可能接近Excel文件中顯示的內容。Apache POI無法檢測到散列格式編號

所以我有這些資料填寫: enter image description here

正如你可以看到,小區內的實際值是166609647,及其與60#############格式化,所以最後我們看到60166609647出現在細胞。

我想捕獲字符串內容爲60166609647在字符串,但到目前爲止,我只能設法捕獲166609647,任何人都可以啓發我什麼是錯的?

注:如果我改變從60############的格式60000000000,我可以捕捉60166609647沒有任何問題,但Excel是通過公共網站上傳的,因此我不能強制執行。

的代碼很簡單,只要:

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) 

庫我使用:

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

有人知道我需要做什麼才能把它弄清楚嗎?

謝謝。

+0

外觀像我的Apache POI錯誤。你有可能寫一個簡短的junit單元測試來展示這個問題,然後在Apache POI bugzilla中打開一個bug。 – Gagravarr

+0

@Gagravarr我已經在https://bz.apache.org/bugzilla/show_bug.cgi?id=61638提交了一個請求,有什麼需要修改的嗎? –

回答

1

問題是多維的。

首先,數字格式60############不能用於應用Java。它導致java.lang.IllegalArgumentException: Malformed pattern "60############"使用DecimalFormat

但是,如果需要的具有「60」爲前綴的每個號碼,則Excel數字格式\6\0#"60"#應該是可能的,並且應當被翻譯成的DecimalFormat圖案'60'#。但apache poiDataFormatter沒有,因爲它只是從Excel的格式字符串中刪除所有引用,這導致60#也是格式不正確。

問題出在DataFormatter.java:671ff

我已經在我的MyDataFormatter修補了這個像這樣:

... 
     // 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; 
    } 
... 

在這個例子中使用這樣的:

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

} 

} 

它導致下面的輸出,如果值是在細胞A1A4格式化爲Excel如圖所示:

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

非常感謝你爲解決這個問題所做的努力。我試圖消化代碼,但根據結果,你是否暗示基本上它不是一個簡單的任務來支持全球支持格式如「60 ####」?好消息是我實際上並不需要檢測小數位和其他複雜的格式,所以如果我可以調用格式化的方法,我想我可以自己複製這些函數,只需要替換所有的' #'到'0',以得到我最終想要的? –

+0

@Chor Wai Chun:正如所說的,數字格式'60 ####'不能用Java的'DecimalFormat'應用。但這對我來說也沒有意義。將所有數字前綴爲「6」,並在數字長度最多爲4位數字前加上0。這意味着什麼?使用我描述的補丁可以將所有數字前綴爲「60」的Excel格式爲「60」#「或」\ 6 \ 0#「。 –

+0

它對世界其他地方實際上毫無意義,除了我們的國家代碼是60的馬來西亞以外,因此我們會將它附加在我們的電話號碼前面以獲得國際格式。我無法控制我的用戶會採用什麼樣的格式,但我可以做的只是爲他們的預測輸入添加儘可能多的支持。所以我想在調用格式函數之前將其格式中的'#'替換爲'0'是我所經歷的最好的選擇。 –