Como posso ler seqüências numéricas nas células do Excel como sequência (não números)?

146
  1. Eu tenho um arquivo excel com esse conteúdo:

    • A1: SomeString

    • A2: 2

    Todos os campos são definidos para o formato String.

  2. Quando leio o arquivo em java usando o POI, ele informa que A2 está no formato de célula numérica.

  3. O problema é que o valor em A2 pode ser 2 ou 2,0 (e eu quero ser capaz de distingui-los), então não posso usar apenas .toString().

O que posso fazer para ler o valor como string?

joycollector
fonte

Respostas:

319

Eu tive o mesmo problema. Eu fiz cell.setCellType(Cell.CELL_TYPE_STRING);antes de ler o valor da string, que resolveu o problema, independentemente de como o usuário formatou a célula.

wil
fonte
Eu uso poi-3.8-beta4, e está funcionando como esperado! Por que os TS não aceitam isso como resposta?
swdev
Esteja ciente de que a conversão numérica de POI para String não leva em consideração a localidade do sistema, ela sempre usa o ponto como um separador decimal. Por exemplo, se o seu sistema usa "," e nos números do Excel se parece com "1,9", o POI retornará "1,9".
Alexey Berezkin
53
Observe que os javadocs do Apache POI explicitamente dizem para não fazer isso! Como eles explicam, você deve usar DataFormatter vez
Gagravarr
6
O aviso de Gagravarr contra fazer isso está certo! Na documentação: "Se o que você deseja fazer é obter um valor String para sua célula numérica, pare !. Essa não é a maneira de fazê-lo. Em vez disso, para buscar o valor da string de uma célula numérica ou booleana ou de data, use DataFormatter. " poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Eu mesmo estava usando essa técnica até acabar alterando acidentalmente os dados que não pretendia mudar. (Defina o tipo para String, valor lido, set tipo de volta para numérico, leia novamente e obter um valor numérico diferente!)
Chris Finley
6
Use DataFormatter. O Javadoc nos adverte de usar o método acima.
Balu SKT
96

Eu não acho que tivemos essa aula de volta quando você fez a pergunta, mas hoje existe uma resposta fácil.

O que você deseja fazer é usar a classe DataFormatter . Você passa essa célula para uma célula e é melhor retornar uma string contendo o que o Excel mostraria para essa célula. Se você passar uma célula de string, você receberá a string de volta. Se você passar uma célula numérica com as regras de formatação aplicadas, ele formatará o número com base nelas e retornará a string.

Para o seu caso, eu suponho que as células numéricas tenham uma regra de formatação inteira aplicada a elas. Se você solicitar ao DataFormatter para formatar essas células, ele retornará uma sequência com a sequência inteira.

Além disso, observe que muitas pessoas sugerem fazer isso cell.setCellType(Cell.CELL_TYPE_STRING), mas os JavaDocs do Apache POI afirmam claramente que você não deve fazer isso ! Fazer a setCellTypechamada perderá a formatação, pois os javadocs explicam que a única maneira de converter para uma String com a formatação restante é usar a classe DataFormatter .

Gagravarr
fonte
Obrigado @Gagravarr apenas sua resposta funciona para mim, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> converte o valor 2.2 como 2.2000000000000002, mas eu quero 2.2. -lo retornar nada em agradecimento formato de cadeia
ankush yadav
dataformatter não parece trabalho para células fórmula, ele retorna uma representação em cadeia da fórmula em vez do valor
gaurav5430
1
Apenas uma observação secundária: forneça trechos de código curto para essas respostas, também se elas estiverem indicadas nos links fornecidos
BAERUS
@ gaurav5430 Sim, ele não combina bem com fórmulas ... De acordo com o 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

O código abaixo funcionou para mim para qualquer tipo de célula.

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
fonte
4
Funcionou muito bem! Minha sugestão seria alterar a maneira como o FormulaEvaluator é recuperado. A classe Pasta de trabalho fornece um avaliador de fórmula através do getCreationHelper().createFormulaEvaluator()método. Dessa forma, seu código não será associado à classe HSSFFormulaEvaluator.
Vitor Santos
Essa deve ser a resposta aceita. Obrigado @Vinayak
Phas1c
Pode FormulaEvaluatorsimplesmente ser removido desta solução? Isso serve a um propósito?
precisa saber é o seguinte
1
a chamada para objFormulaEvaluator.evaluate não é necessária. O valor de retorno disso não está sendo usado aqui.
Radu Simionescu
32

Eu recomendaria a seguinte abordagem ao modificar o tipo de célula é indesejável:

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

NumberToTextConverter pode converter corretamente o valor duplo em um texto usando as regras do Excel sem perda de precisão.

Stanislav Mamontov
fonte
Conselho realmente emocionante! Obrigado! Ele permite obter valores não convertidos em contraste com a configuração cellType como String.
Gleb Egunov 19/06/19
Estou recebendo 44007 como saída para o valor da célula de 25/06/2020. O que estou fazendo de errado?
Vinay
10

Sim, isso funciona perfeitamente

recomendado:

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

velho:

cell.setCellType(Cell.CELL_TYPE_STRING);

mesmo se você tiver um problema ao recuperar um valor da cellfórmula, ainda assim isso funciona.

Rajesh Mbm
fonte
5
Mas você deve ter cuidado ao usar isso para valores duplos. Para mim, virou-se o valor 7,9 para 7,8999956589965 ...
Chris
2
Os javadocs do Apache POI são muito claros: você não deve fazer isso da seguinte maneira : Se o que você deseja fazer é obter um valor String para sua célula numérica, pare !. Esta não é a maneira de fazê-lo. Em vez disso, para buscar o valor da seqüência de caracteres de uma célula numérica ou booleana ou de data, use DataFormatter.
Gagravarr
4

Experimentar:

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

Deve formatar o número corretamente.

eu pego
fonte
Pelo que entendi, o autor da pergunta quer ser capaz de distinguir entre 2e 2.0. Sua solução não faria isso. (Mas ainda assim, bem-vindo ao estouro de pilha!)
Paulo Ebermann
1

Enquanto a célula estiver no formato de texto antes de o usuário digitar o número, o POI permitirá que você obtenha o valor como uma sequência. Uma chave é que, se houver um pequeno triângulo verde no canto superior esquerdo da célula formatado como Texto, você poderá recuperar seu valor como uma string (o triângulo verde aparece sempre que algo que parece ser um número for coagido em um formato de texto). Se você tiver células formatadas em texto que contenham números, mas o POI não permitirá que você busque esses valores como sequências, existem algumas coisas que você pode fazer com os dados da planilha para permitir que:

  • Clique duas vezes na célula para que o cursor de edição esteja presente dentro da célula e clique em Enter (o que pode ser feito apenas uma célula por vez).
  • Use a função de conversão de texto do Excel 2007 (que pode ser feita em várias células ao mesmo tempo).
  • Recorte os valores incorretos para outro local, reformate as células da planilha como texto e repita os valores recortados anteriormente como Valores não formatados novamente na área adequada.

Uma última coisa que você pode fazer é que, se você estiver usando o POI para obter dados de uma planilha do Excel 2007, poderá usar o método 'getRawValue ()' da classe Cell. Isso não se importa com o formato. Ele simplesmente retornará uma string com os dados brutos.

Mark Farnsworth
fonte
0

Quando lemos o valor da célula numérica do MS Excel usando a biblioteca Apache POI, ele é lido como numérico. Mas, em algum momento, queremos que ele seja lido como uma string (por exemplo, números de telefone etc.). Foi assim que eu fiz:

  1. Insira uma nova coluna com a primeira célula = CONCATENATE ("!", D2). Presumo que D2 seja o ID da célula da sua coluna de número de telefone. Arraste a nova célula até o fim.

  2. Agora, se você ler a célula usando o POI, ela lerá a fórmula em vez do valor calculado. Agora faça o seguinte:

  3. Adicione outra coluna

  4. Selecione a coluna completa criada na etapa 1. e escolha Editar-> COPIAR

  5. Vá para a célula superior da coluna criada na etapa 3. e selecione Editar-> Colar Especial

  6. Na janela aberta, selecione o botão de opção "Valores"

  7. Selecione "OK"

  8. Agora leia usando a API POI ... depois de ler em Java ... basta remover o primeiro caractere, ou seja, "!"

Asif Shahzad
fonte
Sua solução parece não ser utilizável se não se produz os arquivos do Excel, é? (Além disso, você pode colocar um extrato em sua resposta Não é tanto tempo?.)
Paulo Ebermann
Sim, não pode ser usado quando não se está produzindo um arquivo excel.
Asif Shahzad
0

Eu também tive um problema semelhante em um conjunto de dados de milhares de números e acho que encontrei uma maneira simples de resolver. Eu precisava inserir o apóstrofo antes de um número para que uma importação de banco de dados separada sempre os visse como texto. Antes disso, o número 8 seria importado como 8.0.

Solução:

  • Mantenha toda a formatação como Geral.
  • Aqui, suponho que os números sejam armazenados na coluna A, iniciando na linha 1.
  • Coloque o 'na coluna B e copie quantas linhas forem necessárias. Nada aparece na planilha. Ao clicar na célula, você pode ver o apóstolo na barra de fórmulas.
  • Na coluna C: = B1 e A1.
  • Selecione todas as células na coluna C e faça um Colar especial na coluna D usando a opção Valores.

Hey Presto todos os números, mas armazenados como texto.

Mark Holmes
fonte
0

getStringCellValue retornará NumberFormatException se o tipo de célula for numérico. Se você não deseja alterar o tipo de célula para string, você pode fazer isso.

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

Muitas dessas respostas referenciam a documentação e as classes antigas de POI. No POI 3.16 mais recente, a célula com os tipos int foi descontinuada

Cell.CELL_TYPE_STRING

insira a descrição da imagem aqui

Em vez disso, o CellType enum pode ser usado.

CellType.STRING 

Apenas certifique-se de atualizar seu pom com a dependência de poi e a dependência de poi-ooxml para a nova versão 3.16, caso contrário você continuará recebendo exceções. Uma vantagem desta versão é que você pode especificar o tipo de célula no momento em que a célula é criada, eliminando todas as etapas extras descritas nas respostas anteriores:

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

Eu preferiria seguir o caminho da resposta do wil ou Vinayak Dornala, infelizmente eles afetaram muito meu desempenho. Fui para uma solução HACKY de elenco implícito:

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

Eu não sugiro que você faça isso, para a minha situação funcionou devido à natureza de como o sistema funcionava e eu tinha uma fonte de arquivo confiável.

Nota de rodapé: numericColumn É um int gerado pela leitura do cabeçalho do arquivo processado.

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

Eu tentei isso e funcionou para mim

Prasanna
fonte
-1

Você controla a planilha do Excel de qualquer maneira? Existe um modelo que os usuários tenham para fornecer a entrada? Nesse caso, você pode formatar o código das células de entrada para você.

datatoo
fonte
-1

Isso funcionou perfeito para mim.

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

Tivemos o mesmo problema e forçamos nossos usuários a formatar as células como 'texto' antes de inserir o valor. Dessa forma, o Excel armazena corretamente números pares como texto. Se o formato for alterado posteriormente, o Excel altera apenas a maneira como o valor é exibido, mas não altera a maneira como o valor é armazenado, a menos que o valor seja inserido novamente (por exemplo, pressionando return quando na célula).

Se o Excel armazenou ou não corretamente o valor como texto é indicado pelo pequeno triângulo verde que o Excel exibe no canto superior esquerdo da célula, se achar que a célula contém um número, mas está formatada como texto.

Turismo
fonte
-3

convertido para um int, então faça a .toString(). É feio, mas funciona.

WolfmanDragon
fonte
O problema é que, se houver 2,0 no A2, preciso obter a string "2.0" e, se 2, a string "2".
28909 joycollector