Làm cách nào tôi có thể đọc các chuỗi số trong các ô Excel dưới dạng chuỗi (không phải số)?


146
  1. Tôi có tệp excel với nội dung như vậy:

    • A1: Một số

    • A2: 2

    Tất cả các trường được đặt thành định dạng Chuỗi.

  2. Khi tôi đọc tệp trong java bằng POI, nó báo rằng A2 ở định dạng ô số.

  3. Vấn đề là giá trị trong A2 có thể là 2 hoặc 2.0 (và tôi muốn có thể phân biệt chúng) vì vậy tôi không thể chỉ sử dụng .toString().

Tôi có thể làm gì để đọc giá trị dưới dạng chuỗi?

Câu trả lời:


319

Tôi đã có vấn đề tương tự. Tôi đã làm cell.setCellType(Cell.CELL_TYPE_STRING);trước khi đọc giá trị chuỗi, giải quyết vấn đề bất kể người dùng định dạng ô như thế nào.


Tôi sử dụng poi-3,8-beta4 và nó hoạt động như mong đợi! Tại sao TS không chấp nhận đây là câu trả lời?
swdev

Xin lưu ý rằng chuyển đổi số thành chuỗi POI không xem xét ngôn ngữ hệ thống, nó luôn sử dụng dấu chấm làm dấu phân cách thập phân. Ví dụ: nếu hệ thống của bạn sử dụng "," và trong các số Excel trông giống như "1,9", POI sẽ trả về "1.9" thay vào đó.
Alexey Berezkin

53
Lưu ý rằng javadocs Apache POI nói rõ ràng không làm điều này! Như họ giải thích, bạn nên sử dụng DataFormatter thay thế
Gagravarr

6
Cảnh báo của Gagravarr chống lại việc này là đúng! Từ các tài liệu: "Nếu những gì bạn muốn làm là lấy giá trị Chuỗi cho ô số của bạn, hãy dừng lại. Đây không phải là cách để làm điều đó. Thay vào đó, để tìm nạp giá trị chuỗi của một ô số hoặc boolean hoặc ngày, hãy sử dụng Thay vào đó, DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/ nam Tôi đã sử dụng kỹ thuật này cho đến khi tôi vô tình thay đổi dữ liệu tôi không có ý định thay đổi. (Đặt loại thành Chuỗi, đọc giá trị, đặt lại thành số, đọc lại và nhận một giá trị số khác!)
Chris Finley

6
Sử dụng DataFormatter. Javadoc cảnh báo chúng tôi sử dụng phương pháp trên.
Balu SKT

96

Tôi không nghĩ rằng chúng tôi đã có lớp học này trở lại khi bạn đặt câu hỏi, nhưng hôm nay có một câu trả lời dễ dàng.

Những gì bạn muốn làm là sử dụng lớp DataFormatter . Bạn truyền cho một ô này và cố gắng trả lại cho bạn một chuỗi chứa những gì Excel sẽ hiển thị cho bạn cho ô đó. Nếu bạn truyền cho nó một ô chuỗi, bạn sẽ lấy lại chuỗi. Nếu bạn truyền cho nó một ô số với các quy tắc định dạng được áp dụng, nó sẽ định dạng số dựa trên chúng và trả lại cho bạn chuỗi.

Đối với trường hợp của bạn, tôi giả sử rằng các ô số có quy tắc định dạng số nguyên được áp dụng cho chúng. Nếu bạn yêu cầu DataFormatter định dạng các ô đó, nó sẽ trả lại cho bạn một chuỗi có chuỗi số nguyên trong đó.

Ngoài ra, lưu ý rằng nhiều người khuyên bạn nên làm cell.setCellType(Cell.CELL_TYPE_STRING), nhưng Apache POI JavaDocs nói rõ rằng bạn không nên làm điều này ! Thực hiện setCellTypecuộc gọi sẽ mất định dạng, vì javadocs giải thích cách duy nhất để chuyển đổi thành Chuỗi với định dạng còn lại là sử dụng lớp DataFormatter .


Cảm ơn @Gagravarr chỉ có câu trả lời của bạn cho tôi, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> khi chuyển đổi giá trị 2.2 thành 2.2000000000000002, nhưng tôi muốn 2.2. nó trả về bất cứ thứ gì ở định dạng chuỗi cảm ơn
ankush yadav

dataformatter dường như không hoạt động cho các ô Công thức, nó trả về một chuỗi đại diện của công thức thay vì giá trị
gaurav5430

1
Chỉ cần một lưu ý nhỏ: Vui lòng cung cấp đoạn mã ngắn cho các câu trả lời như vậy, nếu chúng được nêu trong các liên kết được cung cấp
BAERUS

@ gaurav5430 Vâng, nó không phù hợp với công thức ... Theo tài liệu,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

Các mã dưới đây làm việc cho tôi cho bất kỳ loại tế bào.

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

}

4
Làm việc tốt Đề nghị của tôi sẽ là thay đổi cách lấy Công thứcEvaluator. Lớp Workbook cung cấp một trình đánh giá công thức mặc dù getCreationHelper().createFormulaEvaluator()phương thức. Bằng cách này, mã của bạn sẽ không được kết hợp với lớp HSSFFormulaEvaluator.
Vitor Santos

Đây phải là câu trả lời được chấp nhận. Cảm ơn @Vinayak
Phas1c

Có thể FormulaEvaluatorchỉ đơn giản là bị loại khỏi giải pháp này? Nó phục vụ một mục đích?
P.Brian.Mackey

1
việc gọi tới objFormulaEvaluator.evalu là không cần thiết. Giá trị trả lại của điều đó không được sử dụng ở đây.
Radu Simionescu

32

Tôi muốn giới thiệu cách tiếp cận sau đây khi sửa đổi loại tế bào là không mong muốn:

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

NumberToTextConverter có thể chuyển đổi chính xác giá trị gấp đôi thành văn bản bằng quy tắc của Excel mà không mất độ chính xác.


Lời khuyên thực sự thú vị! Cảm ơn bạn! Nó cho phép nhận các giá trị không được chuyển đổi trái ngược với việc đặt cellType thành Chuỗi.
Gleb Egunov

Tôi nhận được 44007 làm đầu ra cho giá trị ô là 25/06/2020. Tôi đang làm gì sai?
Vinay


10

Vâng, điều này hoạt động hoàn hảo

đề nghị:

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

cũ:

cell.setCellType(Cell.CELL_TYPE_STRING);

ngay cả khi bạn gặp vấn đề với việc truy xuất giá trị từ cellviệc có công thức, thì điều này vẫn hoạt động.


5
Nhưng bạn phải cẩn thận khi sử dụng giá trị này cho giá trị gấp đôi. Đối với tôi, nó đã biến giá trị 7.9 thành 7.8999956589965 ...
Chris

2
Các javadocs Apache POI rất rõ ràng rằng bạn không nên làm như vậy : Nếu điều bạn muốn làm là lấy một giá trị Chuỗi cho ô số của bạn, hãy dừng lại!. Đây không phải là cách để làm điều đó. Thay vào đó, để tìm nạp giá trị chuỗi của một ô số hoặc boolean hoặc ngày, thay vào đó, hãy sử dụng DataFormatter.
Gagravarr

4

Thử:

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

Nên định dạng số chính xác.


Theo tôi hiểu, người hỏi muốn có thể phân biệt giữa 22.0. Giải pháp của bạn sẽ không làm điều này. (Nhưng vẫn vậy, chào mừng bạn đến với Stack Overflow!)
Paŭlo Ebermann

1

Miễn là ô ở định dạng văn bản trước khi người dùng nhập số, POI sẽ cho phép bạn lấy giá trị dưới dạng chuỗi. Một chìa khóa là nếu có một hình tam giác nhỏ màu xanh lá cây ở góc trên bên trái của ô được định dạng là Văn bản, bạn sẽ có thể truy xuất giá trị của nó dưới dạng một chuỗi (hình tam giác màu xanh lá cây xuất hiện bất cứ khi nào có vẻ là một số được ép buộc thành một định dạng văn bản). Nếu bạn có các ô được định dạng văn bản có chứa số, nhưng POI sẽ không cho phép bạn tìm nạp các giá trị đó dưới dạng chuỗi, có một số điều bạn có thể làm với dữ liệu Bảng tính để cho phép:

  • Nhấp đúp chuột vào ô để con trỏ chỉnh sửa hiện diện bên trong ô, sau đó nhấp vào Enter (chỉ có thể được thực hiện một ô mỗi lần).
  • Sử dụng chức năng chuyển đổi văn bản Excel 2007 (có thể được thực hiện trên nhiều ô cùng một lúc).
  • Cắt các giá trị vi phạm sang một vị trí khác, định dạng lại các ô của bảng tính dưới dạng văn bản, sau đó chọn lại các giá trị đã cắt trước đó dưới dạng Giá trị không được định dạng trở lại khu vực thích hợp.

Một điều cuối cùng mà bạn có thể làm là nếu bạn đang sử dụng POI để lấy dữ liệu từ bảng tính Excel 2007, bạn có thể sử dụng phương thức 'getRawValue ()' của lớp Cell. Điều này không quan tâm định dạng là gì. Nó chỉ đơn giản sẽ trả về một chuỗi với dữ liệu thô.


0

Khi chúng tôi đọc giá trị ô số của MS Excel bằng thư viện Apache POI, nó sẽ đọc nó dưới dạng số. Nhưng đôi khi chúng tôi muốn nó đọc dưới dạng chuỗi (ví dụ số điện thoại, v.v.). Đây là cách tôi đã làm nó:

  1. Chèn một cột mới với ô đầu tiên = CONCATENATE ("!", D2). Tôi giả sử D2 là id ô của cột số điện thoại của bạn. Kéo ô mới lên đến hết.

  2. Bây giờ nếu bạn đọc ô bằng POI, nó sẽ đọc công thức thay vì giá trị được tính. Bây giờ làm như sau:

  3. Thêm một cột khác

  4. Chọn cột hoàn chỉnh được tạo trong bước 1. và chọn Chỉnh sửa-> SAO CHÉP

  5. Chuyển đến ô trên cùng của cột được tạo ở bước 3. và chọn Chỉnh sửa-> Dán đặc biệt

  6. Trong cửa sổ mở, chọn nút radio "Giá trị"

  7. Chọn "OK"

  8. Bây giờ hãy đọc bằng API POI ... sau khi đọc bằng Java ... chỉ cần xóa ký tự đầu tiên tức là "!"


Giải pháp của bạn dường như không thể sử dụng được nếu một người không tự sản xuất các tệp excel, phải không? (Ngoài ra, bạn có thể đặt một đoạn trích vào câu trả lời của mình không? Nó không dài lắm đâu.)
Paŭlo Ebermann

Có, nó không thể được sử dụng khi một người không tự sản xuất tệp excel.
Asif Shahzad

0

Tôi cũng đã có một vấn đề tương tự trên một tập hợp dữ liệu gồm hàng ngàn số và tôi nghĩ rằng tôi đã tìm thấy một cách đơn giản để giải quyết. Tôi cần phải đưa dấu nháy vào trước một số để nhập DB riêng biệt luôn xem các số dưới dạng văn bản. Trước đó, số 8 sẽ được nhập là 8.0.

Giải pháp:

  • Giữ tất cả các định dạng như Chung.
  • Ở đây tôi giả sử các số được lưu trữ trong Cột A bắt đầu từ Hàng 1.
  • Đặt vào 'trong Cột B và sao chép xuống càng nhiều hàng nếu cần. Không có gì xuất hiện trong bảng tính nhưng nhấp vào ô bạn có thể thấy dấu nháy đơn trong thanh Công thức.
  • Trong Cột C: = B1 & A1.
  • Chọn tất cả các ô trong Cột C và thực hiện Dán đặc biệt vào Cột D bằng tùy chọn Giá trị.

Hey Presto tất cả các số nhưng được lưu dưới dạng Văn bản.


0

getStringCellValue trả về NumberFormatException nếu loại ô là số. Nếu bạn không muốn thay đổi loại ô thành chuỗi, bạn có thể làm điều này.

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

0

Nhiều câu trả lời tham khảo tài liệu và lớp học POI cũ. Trong POI 3.16 mới nhất, Cell với các kiểu int đã không được dùng nữa

Cell.CELL_TYPE_STRING

nhập mô tả hình ảnh ở đây

Thay vào đó, enum CellType có thể được sử dụng.

CellType.STRING 

Chỉ cần đảm bảo cập nhật pom của bạn với phụ thuộc poi cũng như phụ thuộc poi-ooxml vào phiên bản 3.16 mới nếu không bạn sẽ tiếp tục gặp ngoại lệ. Một lợi thế với phiên bản này là bạn có thể chỉ định loại ô tại thời điểm ô được tạo loại bỏ tất cả các bước bổ sung được mô tả trong các câu trả lời trước:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);

0

Tôi thà đi theo con đường của câu trả lời của wil hoặc Vinayak Dornala, tiếc là họ đã làm ảnh hưởng đến hiệu suất của tôi rất nhiều. Tôi đã đi đến một giải pháp HACKY của đúc ngầm:

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

Tôi không đề nghị bạn làm điều này, vì tình huống của tôi nó hoạt động vì bản chất của cách hệ thống hoạt động và tôi có một nguồn tệp đáng tin cậy.

Chú thích: numColumn Là một int được tạo từ việc đọc tiêu đề của tệp được xử lý.


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

Tôi đã thử cái này và nó làm việc cho tôi


-1

Bạn có kiểm soát bảng tính excel không? Có một mẫu mà người dùng đã cung cấp cho bạn đầu vào? Nếu vậy, bạn có thể có định dạng mã cho các ô nhập cho bạn.




-1

Điều này làm việc hoàn hảo cho tôi.

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

-2

Chúng tôi đã có cùng một vấn đề và buộc người dùng của chúng tôi phải định dạng các ô là 'văn bản' trước đó nhập giá trị. Bằng cách đó, Excel lưu trữ chính xác các số chẵn dưới dạng văn bản. Nếu định dạng được thay đổi sau đó, Excel chỉ thay đổi cách hiển thị giá trị nhưng không thay đổi cách lưu trữ giá trị trừ khi giá trị được nhập lại (ví dụ: bằng cách nhấn return khi ở trong ô).

Có hay không Excel lưu trữ chính xác giá trị dưới dạng văn bản được biểu thị bằng hình tam giác nhỏ màu xanh lá cây mà Excel hiển thị ở góc trên bên trái của ô nếu nó nghĩ ô chứa một số nhưng được định dạng là văn bản.


-3

đúc đến một int sau đó làm a .toString(). Nó là xấu xí nhưng nó hoạt động.


Vấn đề là nếu có 2.0 trong A2 tôi cần lấy chuỗi "2.0" và nếu 2 thì chuỗi "2".
joycollector
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.