¿Cómo puedo leer cadenas numéricas en celdas de Excel como cadenas (no números)?

146
  1. Tengo un archivo de Excel con tales contenidos:

    • A1: SomeString

    • A2: 2

    Todos los campos están configurados en formato de cadena.

  2. Cuando leo el archivo en Java usando POI, me dice que A2 está en formato de celda numérica.

  3. El problema es que el valor en A2 puede ser 2 o 2.0 (y quiero poder distinguirlos), así que no puedo usarlo .toString().

¿Qué puedo hacer para leer el valor como cadena?

joycollector
fuente

Respuestas:

319

Tuve el mismo problema Lo hice cell.setCellType(Cell.CELL_TYPE_STRING);antes de leer el valor de la cadena, que resolvió el problema independientemente de cómo el usuario formateó la celda.

wil
fuente
Yo uso poi-3.8-beta4, ¡y funciona como se esperaba! ¿Por qué TS no acepta esto como la respuesta?
swdev
Tenga en cuenta que la conversión numérica de POI a cadena no tiene en cuenta la configuración regional del sistema, siempre utiliza el punto como separador decimal. Por ejemplo, si su sistema usa "," y en Excel los números se ven como "1,9", POI devolverá "1.9" en su lugar.
Alexey Berezkin
53
Tenga en cuenta que los javadocs de PDI de Apache dicen explícitamente que no hagan esto. Como explican, debería usar DataFormatter en su lugar
Gagravarr
66
¡La advertencia de Gagravarr contra hacer esto es correcta! De los documentos: "Si lo que quieres hacer es obtener un valor de cadena para tu celda numérica, ¡detente! Esta no es la forma de hacerlo. En cambio, para obtener el valor de cadena de una celda numérica, booleana o de fecha, usa DataFormatter en su lugar ". poi.apache.org/apidocs/org/apache/poi/ss/usermodel/… Estaba usando esta técnica yo mismo hasta que terminé cambiando accidentalmente datos que no pretendía cambiar. (Establezca el tipo en Cadena, lea el valor, vuelva a configurar el tipo en numérico, ¡lea de nuevo y obtenga un valor numérico diferente!)
Chris Finley
66
Use DataFormatter. El Javadoc nos advierte del uso del método anterior.
Balu SKT
96

No creo que tuviéramos esta clase cuando hiciste la pregunta, pero hoy hay una respuesta fácil.

Lo que quieres hacer es usar la clase DataFormatter . Se le pasa esta celda y hace todo lo posible para devolverle una cadena que contiene lo que Excel le mostrará para esa celda. Si le pasa una celda de cadena, recuperará la cadena. Si le pasa una celda numérica con reglas de formato aplicadas, formateará el número en función de ellas y le devolverá la cadena.

Para su caso, supongo que las celdas numéricas tienen aplicada una regla de formato entero. Si le pide a DataFormatter que formatee esas celdas, le devolverá una cadena con la cadena entera.

Además, tenga en cuenta que mucha gente sugiere hacerlo cell.setCellType(Cell.CELL_TYPE_STRING), pero los JavaDoc de PDI de Apache indican claramente que no debe hacer esto . Hacer la setCellTypellamada perderá el formato, ya que los javadocs explican que la única forma de convertir a una Cadena con formato restante es usar la clase DataFormatter .

Gagravarr
fuente
Gracias @Gagravarr solo su respuesta funciona para mí, <code> cell.setCellType (Cell.CELL_TYPE_STRING); <code> en convertir el valor 2.2 como 2.2000000000000002, pero quiero 2.2. devuelve cualquier cosa en formato de cadena gracias
ankush yadav
El formateador de datos no parece funcionar para las celdas de Fórmula, devuelve una representación de cadena de la fórmula en lugar del valor
gaurav5430
1
Solo una pequeña nota: proporcione fragmentos de código cortos para tales respuestas, también si se indican en los enlaces provistos
BAERUS
@ gaurav5430 Sí, no va bien con las fórmulas ... Según el documento,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

El siguiente código funcionó para mí para cualquier tipo de celda.

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
fuente
44
Funcionó muy bien! Mi sugerencia sería cambiar la forma en que se recupera el FormulaEvaluator. La clase Workbook proporciona un evaluador de fórmulas a través del getCreationHelper().createFormulaEvaluator()método. De esta manera, su código no se combinará con la clase HSSFFormulaEvaluator.
Vitor Santos
Esta debería ser la respuesta aceptada. Gracias @Vinayak
Phas1c
¿ FormulaEvaluatorSimplemente se puede eliminar de esta solución? ¿Sirve para un propósito?
P.Brian.Mackey
1
la llamada a objFormulaEvaluator.evaluate no es necesaria. El valor de retorno de eso no se está utilizando aquí.
Radu Simionescu
32

Recomendaría el siguiente enfoque cuando modificar el tipo de celda no es deseable:

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

NumberToTextConverter puede convertir correctamente el valor doble en un texto utilizando las reglas de Excel sin pérdida de precisión.

Stanislav Mamontov
fuente
Consejo realmente emocionante! ¡Gracias! Permite obtener valores no convertidos en contraste con establecer cellType en String.
Gleb Egunov
Estoy obteniendo 44007 como salida para el valor de celda del 25/06/2020. ¿Qué estoy haciendo mal?
Vinay
10

Si, esto funciona perfectamente

recomendado:

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

antiguo:

cell.setCellType(Cell.CELL_TYPE_STRING);

incluso si tiene un problema con recuperar un valor de celltener fórmula, aún así funciona.

Rajesh Mbm
fuente
55
Pero debe tener cuidado al usar esto para valores dobles. Para mí, convirtió el valor 7.9 en 7.8999956589965 ...
Chris
2
Los javadocs de PDI de Apache son muy claros de que no debería hacerlo así : si lo que desea hacer es obtener un valor de cadena para su celda numérica, ¡deténgase! Esta no es la manera de hacerlo. En su lugar, para obtener el valor de cadena de una celda numérica, booleana o de fecha, use DataFormatter en su lugar.
Gagravarr
4

Tratar:

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

Debe formatear el número correctamente.

tomo
fuente
Según tengo entendido, el autor de la pregunta quiere poder distinguir entre 2y 2.0. Tu solución no haría esto. (¡Pero aún así, bienvenido a Stack Overflow!)
Paŭlo Ebermann
1

Mientras la celda esté en formato de texto antes de que el usuario ingrese el número, POI le permitirá obtener el valor como una cadena. Una clave es que si hay un pequeño triángulo verde en la esquina superior izquierda de la celda con formato de Texto, podrá recuperar su valor como una cadena (el triángulo verde aparece cada vez que algo parece ser un número es forzado a un formato de texto). Si tiene celdas con formato de texto que contienen números, pero POI no le permitirá recuperar esos valores como cadenas, hay algunas cosas que puede hacer con los datos de la hoja de cálculo para permitir eso:

  • Haga doble clic en la celda para que el cursor de edición esté presente dentro de la celda, luego haga clic en Enter (que se puede hacer solo una celda a la vez).
  • Use la función de conversión de texto de Excel 2007 (que se puede hacer en varias celdas a la vez).
  • Recorte los valores ofensivos en otra ubicación, vuelva a formatear las celdas de la hoja de cálculo como texto, luego vuelva a pegar los valores recortados previamente como Valores sin formato en el área adecuada.

Una última cosa que puede hacer es que si está utilizando POI para obtener datos de una hoja de cálculo de Excel 2007, puede usar el método 'getRawValue ()' de la clase Cell. Esto no le importa cuál es el formato. Simplemente devolverá una cadena con los datos sin procesar.

Mark Farnsworth
fuente
0

Cuando leemos el valor de celda numérica de MS Excel usando la biblioteca Apache POI, lo lee como numérico. Pero en algún momento queremos que se lea como una cadena (por ejemplo, números de teléfono, etc.). Así es como lo hice:

  1. Inserte una nueva columna con la primera celda = CONCATENAR ("!", D2). Supongo que D2 es la identificación de la celda de su columna de número de teléfono. Arrastre la nueva celda hasta el final.

  2. Ahora, si lee la celda usando POI, leerá la fórmula en lugar del valor calculado. Ahora haz lo siguiente:

  3. Agregar otra columna

  4. Seleccione la columna completa creada en el paso 1. y elija Editar-> COPIAR

  5. Vaya a la celda superior de la columna creada en el paso 3. y seleccione Editar-> Pegado especial

  6. En la ventana abierta, seleccione el botón de opción "Valores"

  7. Seleccione "OK"

  8. Ahora lea usando POI API ... después de leer en Java ... simplemente elimine el primer carácter, es decir, "!"

Asif Shahzad
fuente
Su solución parece no ser utilizable si uno no produce los archivos de Excel, ¿verdad? (También, se puede poner un extracto en su respuesta no es tan largo?.)
Paulo Ebermann
Sí, no se puede usar cuando uno no está produciendo un archivo Excel.
Asif Shahzad
0

También he tenido un problema similar en un conjunto de datos de miles de números y creo que he encontrado una manera simple de resolverlo. Necesitaba insertar el apóstrofe antes de un número para que una importación de DB por separado siempre vea los números como texto. Antes de esto, el número 8 se importaría como 8.0.

Solución:

  • Mantenga todo el formato como General.
  • Aquí supongo que los números se almacenan en la Columna A a partir de la Fila 1.
  • Ponga el 'en la columna B y copie tantas filas como sea necesario. No aparece nada en la hoja de trabajo, pero al hacer clic en la celda puede ver el apóstofo en la barra de fórmulas.
  • En la columna C: = B1 y A1.
  • Seleccione todas las Celdas en la Columna C y haga un Pegado Especial en la Columna D usando la opción Valores.

Hola Presto todos los números pero almacenados como texto.

Mark Holmes
fuente
0

getStringCellValue devuelve NumberFormatException si el tipo de celda es numérico. Si no desea cambiar el tipo de celda a cadena, puede hacerlo.

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

Muchas de estas respuestas hacen referencia a documentación y clases antiguas de PDI. En el POI 3.16 más reciente, la celda con los tipos int ha quedado en desuso

Cell.CELL_TYPE_STRING

ingrese la descripción de la imagen aquí

En cambio, se puede usar la enumeración CellType .

CellType.STRING 

Solo asegúrese de actualizar su pom con la dependencia poi, así como la dependencia poi-ooxml a la nueva versión 3.16, de lo contrario, continuará recibiendo excepciones. Una ventaja de esta versión es que puede especificar el tipo de celda en el momento en que se crea la celda, eliminando todos los pasos adicionales descritos en las respuestas anteriores:

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

Preferiría seguir la ruta de la respuesta de Wil o Vinayak Dornala, desafortunadamente afectaron mi actuación demasiado. Fui por una solución HACKY de casting implícito:

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

No le sugiero que haga esto, para mi situación funcionó debido a la naturaleza de cómo funcionaba el sistema y tenía un origen de archivos confiable.

Nota al pie: numericColumn Es un int que se genera al leer el encabezado del archivo procesado.

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

Intenté esto y funcionó para mí

Prasanna
fuente
-1

¿Controlas la hoja de cálculo de Excel de todos modos? ¿Hay una plantilla que los usuarios tienen para darle la entrada? Si es así, puede hacer que el código formatee las celdas de entrada por usted.

datatoo
fuente
-1

Esto funcionó perfecto para mí.

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

Tuvimos el mismo problema y obligamos a nuestros usuarios a formatear las celdas como 'texto' antes de ingresar el valor. De esa manera, Excel almacena correctamente los números pares como texto. Si luego se cambia el formato, Excel solo cambia la forma en que se muestra el valor, pero no cambia la forma en que se almacena el valor, a menos que el valor se ingrese nuevamente (por ejemplo, presionando Intro cuando está en la celda).

Si Excel almacenó correctamente o no el valor como texto se indica mediante el pequeño triángulo verde que Excel muestra en la esquina superior izquierda de la celda si cree que la celda contiene un número pero está formateado como texto.

Turismo
fuente
-3

emitir a un int luego hacer un .toString(). Es feo pero funciona.

WolfmanDragon
fuente
El problema es que si hay 2.0 en A2, necesito obtener la cadena "2.0", y si es 2, entonces la cadena "2".
joycollector