Excel hücrelerindeki sayısal dizeleri dize (sayı değil) olarak nasıl okuyabilirim?


150
  1. Bu tür içeriklere sahip excel dosyam var:

    • A1: Bazı Dizeler

    • A2: 2

    Tüm alanlar Dize formatına ayarlanmıştır.

  2. POI kullanarak java dosyasını okuduğumda, A2'nin sayısal hücre formatında olduğunu söylüyor.

  3. Sorun şu ki, A2'deki değer 2 veya 2.0 olabilir (ve onları ayırt edebilmek istiyorum), bu yüzden sadece kullanamam .toString().

Değeri string olarak okumak için ne yapabilirim?

Yanıtlar:


328

Aynı problemim vardı. cell.setCellType(Cell.CELL_TYPE_STRING);Kullanıcının hücreyi nasıl biçimlendirdiğine bakılmaksızın sorunu çözen dize değerini okumadan önce yaptım .


Poi-3.8-beta4 kullanıyorum ve beklendiği gibi çalışıyor! TS bunu neden cevap olarak kabul etmiyor?
swdev

POI sayısaldan Dize dönüşümüne, sistem yerel ayarını dikkate almadığına, noktayı her zaman ondalık ayırıcı olarak kullanır. Örneğin, sisteminiz "," kullanıyorsa ve Excel'de sayılar "1,9" gibi görünüyorsa, POI bunun yerine "1.9" döndürür.
Alexey Berezkin


6
Gagravarr'ın bunu yapmama uyarısı doğru! Dokümanlardan: "Yapmak istediğiniz, sayısal hücreniz için bir Dize değeri almaksa, durun! Bunu yapmanın yolu bu değildir. Bunun yerine, sayısal veya boole veya tarih hücresinin dize değerini almak için şunu kullanın: Bunun yerine DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Değiştirmek istemediğim verileri yanlışlıkla değiştirene kadar bu tekniği kendim kullanıyordum. (Türü Dize olarak ayarlayın, değeri okuyun, türü tekrar sayısal olarak ayarlayın, tekrar okuyun ve farklı bir sayısal değer alın!)
Chris Finley

6
DataFormatter'ı kullanın. Javadoc bizi yukarıdaki yöntemi kullanmamız konusunda uyarıyor.
Balu SKT

99

Soruyu sorduğunuzda bu dersi geri aldığımızı sanmıyorum, ama bugün kolay bir cevap var.

Yapmak istediğiniz şey DataFormatter sınıfını kullanmaktır . Bunu bir hücreye iletirsiniz ve o, size Excel'in o hücre için göstereceği şeyi içeren bir dize döndürmek için elinden geleni yapar. Bir dizeli hücre geçirirseniz, dizeyi geri alırsınız. Biçimlendirme kurallarının uygulandığı sayısal bir hücreye iletirseniz, sayıyı bunlara göre biçimlendirir ve dizeyi size geri verir.

Sizin durumunuz için, sayısal hücrelerin kendilerine uygulanan bir tamsayı biçimlendirme kuralına sahip olduğunu varsayarım. DataFormatter'dan bu hücreleri biçimlendirmesini isterseniz, size içinde tamsayı dizesi olan bir dize verir.

Ayrıca, birçok insanın yapmayı önerdiğini unutmayın cell.setCellType(Cell.CELL_TYPE_STRING), ancak Apache POI JavaDoc'ları bunu yapmamanız gerektiğini açıkça belirtir ! Javadocs , kalan biçimlendirme ile bir String'e dönüştürmenin tek yolunun DataFormatter sınıfını kullanmak olduğunu açıkladığından , setCellTypeçağrıyı yapmak biçimlendirmeyi gevşetecektir .


Teşekkürler @Gagravarr sadece cevabınız benim için çalışıyor, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> 2.2 değerini 2.2000000000000002 olarak dönüştürmek ama 2.2 istiyorum. dize biçiminde her şeyi döndürür, teşekkürler
ankush yadav

dataformatter Formül hücreleri için çalışmıyor gibi görünüyor, değer yerine formülün bir dize gösterimini döndürüyor
gaurav5430

1
Sadece bir küçük not: Lütfen bu tür cevaplar için kısa kod parçacıkları sağlayın, ayrıca verilen bağlantılarda da belirtilmişse
BAERUS

@ gaurav5430 Evet, formüllerle iyi gitmiyor ... When passed a null or blank cell, this method will return an empty String (""). Formulas in formula type cells will not be evaluated.
Dokümana

56

Aşağıdaki kod, her tür hücre için benim için çalıştı.

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

}

5
Gayet iyi çalıştı! Benim önerim, FormulaEvaluator'ın alınma şeklini değiştirmek olacaktır. Workbook sınıfı, yöntemle birlikte bir formül değerlendirici sağlar getCreationHelper().createFormulaEvaluator(). Bu şekilde kodunuz HSSFFormulaEvaluator sınıfı ile birleştirilmeyecektir.
Vitor Santos

Kabul edilen cevap bu olmalıdır. Teşekkürler @Vinayak
Phas1c

Can FormulaEvaluatorbasitçe bu çözümün kaldırılacak? Bir amaca hizmet ediyor mu?
P. Brian.Mackey

1
objFormulaEvaluator.evaluate çağrısı gerekli değildir. Bunun dönüş değeri burada kullanılmıyor.
Radu Simionescu

33

Hücrenin türünü değiştirmek istenmeyen bir durum olduğunda aşağıdaki yaklaşımı tavsiye ederim:

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

NumberToTextConverter, çift değeri Excel'in kurallarını kullanarak hassasiyet kaybı olmadan doğru bir şekilde metne dönüştürebilir.


Gerçekten heyecan verici bir tavsiye! Teşekkür ederim! CellType'ı String olarak ayarlamanın aksine dönüştürülmemiş değerleri elde etmeye izin verir.
Gleb Egunov

25/06/2020 hücre değeri için çıktı olarak 44007 alıyorum. Neyi yanlış yapıyorum?
Vinay

@Vinay tarihler için DateUtil kullanın. Gibi bir şeyDateUtil.getLocalDateTime(row.getCell(1).getNumericCellValue()).toLocalDate()
Georgy Bolyuba


10

Evet, bu mükemmel çalışıyor

önerilen:

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

eski:

cell.setCellType(Cell.CELL_TYPE_STRING);

cellFormüle sahip olmaktan bir değeri almakla ilgili bir sorununuz olsa bile , bu yine de işe yarar .


5
Ancak bunu çift değerler için kullanırken dikkatli olmalısınız. Benim için 7,9 değerini 7,8999956589965'e çevirdi ...
Chris

2
Apache POI Javadocs bunu böyle yapıyor olması gerektiğini çok açık : ne yapmak istediğiniz sayısal hücre için bir dize değeri elde ise, durdurma !. Bunu yapmanın yolu bu değil. Bunun yerine, sayısal veya boole veya tarih hücresinin dize değerini almak için bunun yerine DataFormatter'ı kullanın.
Gagravarr

4

Deneyin:

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

Numarayı doğru biçimlendirmelidir.


Anlıyorum gibi, asker ayırt edebilmek istiyor 2ve 2.0. Çözümünüz bunu yapmaz. (Ama yine de Stack Overflow'a hoş geldiniz!)
Paŭlo Ebermann

1

Kullanıcı numarayı girmeden önce hücre metin biçiminde olduğu sürece, POI değeri bir dizge olarak almanıza izin verecektir. Önemli olanlardan biri, hücrenin sol üst köşesinde Metin olarak biçimlendirilmiş küçük bir yeşil üçgen varsa, değerini bir dize olarak alabilmenizdir (yeşil üçgen, bir şey sayı gibi göründüğünde görünür. bir metin biçimine zorlanır). Sayılar içeren Metin biçimlendirilmiş hücreleriniz varsa, ancak İÇN bu değerleri dize olarak getirmenize izin vermiyorsa, buna izin vermek için Elektronik Tablo verilerine yapabileceğiniz birkaç şey vardır:

  • Düzenleme imlecinin hücrenin içinde olması için hücreye çift tıklayın, ardından Enter'a tıklayın (bir seferde yalnızca bir hücre yapılabilir).
  • Excel 2007 metin dönüştürme işlevini kullanın (aynı anda birden çok hücrede yapılabilir).
  • Rahatsız edici değerleri başka bir konuma kesin, elektronik tablo hücrelerini metin olarak yeniden biçimlendirin, ardından önceden kesilmiş değerleri Biçimlendirilmemiş Değerler olarak yeniden uygun alana yapıştırın .

Yapabileceğiniz son bir şey, bir Excel 2007 elektronik tablosundan veri almak için POI kullanıyorsanız, Cell sınıfı 'getRawValue ()' yöntemini kullanabilmenizdir. Bu formatın ne olduğu umurunda değil. Ham verileri içeren bir dize döndürür.


0

MS Excel'in sayısal hücre değerini Apache POI kitaplığını kullanarak okuduğumuzda, onu sayısal olarak okur. Ama bazen dizge olarak okunmasını isteriz (örneğin telefon numaraları vb.). Ben böyle yaptım:

  1. İlk hücre = CONCATENATE ("!", D2) olan yeni bir sütun ekleyin. D2'nin telefon numarası sütununun hücre kimliği olduğunu varsayıyorum. Yeni hücreyi sonuna kadar sürükleyin.

  2. Şimdi, POI'yi kullanarak hücreyi okursanız, hesaplanan değer yerine formülü okuyacaktır. Şimdi şunları yapın:

  3. Başka bir sütun ekle

  4. 1. adımda oluşturulan tam sütunu seçin ve Düzen-> KOPYALA'yı seçin.

  5. 3. adımda oluşturulan sütunun en üst hücresine gidin ve Düzen-> Özel Yapıştır'ı seçin

  6. Açılan pencerede "Değerler" radyo düğmesini seçin

  7. "Tamam" ı seçin

  8. Şimdi POI API kullanarak okuyun ... Java'da okuduktan sonra ... sadece ilk karakteri, yani "!"


Excel dosyalarını kendisi üretmezse çözümünüz kullanılamaz gibi görünüyor, değil mi? (Ayrıca cevabınıza bir alıntı
ekleyebilir

Evet, kendisi excel dosyası üretmediğinde kullanılamaz.
Asif Shahzad

0

Binlerce sayıdan oluşan bir veri setinde de benzer bir sorun yaşadım ve çözmenin basit bir yolunu bulduğumu düşünüyorum. Bir sayıdan önce kesme işaretinin eklenmesini sağlamam gerekiyordu, böylece ayrı bir DB içe aktarma işlemi sayıları her zaman metin olarak görür. Bundan önce 8 rakamı 8.0 olarak ithal edilecek.

Çözüm:

  • Tüm biçimlendirmeyi Genel olarak koruyun.
  • Burada, sayıların Satır 1'den başlayarak Sütun A'da depolandığını varsayıyorum.
  • Sütun B'yi yerleştirin ve gerektiği kadar çok satırı kopyalayın. Çalışma sayfasında hiçbir şey görünmez ancak hücreye tıkladığınızda apostofeyi Formül çubuğunda görebilirsiniz.
  • C Sütununda: = B1 & A1.
  • C Sütunundaki tüm Hücreleri seçin ve Değerler seçeneğini kullanarak Sütun D'ye Özel Yapıştır yapın.

Hey, tüm numaralar ancak Metin olarak saklanır.


0

Hücre türü sayısal ise getStringCellValue NumberFormatException döndürür. Hücre türünü dizeye değiştirmek istemiyorsanız, bunu yapabilirsiniz.

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

0

Bu yanıtların çoğu eski POI belgelerine ve sınıflarına atıfta bulunur. En yeni POI 3.16'da, int türlerine sahip hücre kullanımdan kaldırıldı

Cell.CELL_TYPE_STRING

görüntü açıklamasını buraya girin

Bunun yerine CellType numaralandırması kullanılabilir.

CellType.STRING 

Sadece pom'unuzu poi bağımlılığı ve poi-ooxml bağımlılığı ile yeni 3.16 sürümüne güncellediğinizden emin olun, aksi takdirde istisnalar almaya devam edersiniz. Bu sürümün bir avantajı, önceki yanıtlarda açıklanan tüm ekstra adımları ortadan kaldırarak hücre oluşturulduğu anda hücre türünü belirtebilmenizdir:

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

0

Bu benim için mükemmel çalıştı.

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

0

Wil'in cevabının veya Vinayak Dornala'nın rotasına gitmeyi tercih ederim, maalesef performansımı çok etkilediler. Örtük döküm için HACKY çözümüne gittim :

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

Bunu yapmanızı önermiyorum, benim durumum için sistemin nasıl çalıştığının doğası gereği çalıştı ve güvenilir bir dosya kaynağım vardı.

Dipnot: numericColumn İşlenen dosyanın başlığının okunmasıyla oluşturulan bir int.


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

Bunu denedim ve benim için çalıştı


-1

Excel çalışma sayfasını yine de kontrol ediyor musunuz? Kullanıcıların size girişi vermek için sahip oldukları bir şablon var mı? Eğer öyleyse, giriş hücrelerini sizin için kod formatına sahip olabilirsiniz.




-2

Aynı sorunu yaşadık ve kullanıcılarımızı değeri girmeden önce hücreleri 'metin' olarak biçimlendirmeye zorladık . Bu şekilde Excel, çift sayıları metin olarak doğru şekilde depolar. Biçim daha sonra değiştirilirse, Excel yalnızca değerin görüntülenme şeklini değiştirir, ancak değer yeniden girilmedikçe değerin saklanma şeklini değiştirmez (örn. Hücre içindeyken return tuşuna basarak).

Excel'in değeri metin olarak doğru şekilde saklayıp saklamadığı, hücrenin bir sayı içerdiğini ancak metin olarak biçimlendirildiğini düşünüyorsa, Excel'in hücrenin sol üst köşesinde görüntülediği küçük yeşil üçgenle gösterilir.


-3

bir int'e çevirin ve sonra a yapın .toString(). Çirkin ama işe yarıyor.


Sorun şu ki, A2'de 2.0 varsa "2.0" dizesini ve 2 ise "2" dizisini almam gerekiyor.
joycollector
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.