在java中使用apache事件模型解析excel文件时,如何检查字符串中的数字包含日期和指数

我正在解析一个excel文件,其中包含许多日期,如13-4-2021和一些数字,这3,7%,2,65%格式。所以我正在解析那个excel文件,我得到一个字符串中的数据写他们在一个文本文件中。所以我的问题是我得到了一个像44299这样的整数的日期,而它实际上是在excel工作表中的04/13/2021格式。另一个案例是我有一些像百分比一样的数字3,7%,2,65%即将到来,如3.6999999999999998E-2。所以我可以将数字转换成日期使用

SimpleDateFormat("MM/dd/yyyy").format(javaDate) 

这是我正在使用的代码

 private static class SheetHandler extends DefaultHandler { private SharedStringsTable sst; private String lastContents; private boolean nextIsString; private int rowNumber; private SheetHandler(SharedStringsTable sst) { this.sst = sst; } public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { try { // row => row if(name.equals("row")) { if (attributes.getValue("r") != null) { rowNumber = Integer.valueOf(attributes.getValue("r")); } else { rowNumber++; } //System.out.println("row: " + rowNumber); } if (rowNumber > 6) { // c => cell if(name.equals("c")) { // Print the cell reference //System.out.print(attributes.getValue("r") + " - "); // Figure out if the value is an index in the SST String cellType = attributes.getValue("t"); if(cellType != null && cellType.equals("s")) { nextIsString = true; } else { nextIsString = false; } } // Clear contents cache lastContents = ""; } }catch(Exception e) { e.printStackTrace(); } } public void endElement(String uri, String localName, String name) throws SAXException { // Process the last contents as required. // Do now, as characters() may be called more than once if (rowNumber > 6) { if(nextIsString) { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); nextIsString = false; } // v => contents of a cell // Output after we've seen the string contents if(name.equals("v")) { // System.out.println(lastContents); if(!lastContents.isEmpty() ) // Here i am putting the values to a list to process pickUpExcelValues.add(lastContents); } } } public void characters(char[] ch, int start, int length) throws SAXException { lastContents += new String(ch, start, length); } } 

但我怎么检查字符串包含让我们说44299是一个约会? 而且我也不知道在写入文本文件时如何将此3.6999999999999998E-2转换为3,7%。如果有任何人有任何想法请帮助。

这个问题需要进一步解释。

首先,它与如何使用已回答的apache事件用户模型跳过xlsm文件中的行有关。

但是,如果想要使用XSSF和SAX(事件API)中的示例,则需要有关Office Open XML中使用的XML基本知识。

ExampleEventUserModel是一个非常低级的示例,显示了流的原理。 为了扩展这一点,需要考虑格式需要解析样式表,然后使用DataFormatter 。

以下是一个完整的例子。 但是有一个更全面的例子,包括支持获取数字格式信息并将其应用于数字单元格(例如,格式化日期或百分比)。 请参阅svn中的XLSX2CSV示例 。

 import java.io.InputStream; import java.util.Iterator; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.BuiltinFormats; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.util.SAXHelper; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; public class ExampleEventUserModel { public void processOneSheet(String filename) throws Exception { OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader( pkg ); SharedStringsTable sst = r.getSharedStringsTable(); StylesTable st = r.getStylesTable(); XMLReader parser = fetchSheetParser(sst, st); // To look up the Sheet Name / Sheet Order / rID, // you need to process the core Workbook stream. // Normally it's of the form rId# or rSheet# InputStream sheet2 = r.getSheet("rId2"); InputSource sheetSource = new InputSource(sheet2); parser.parse(sheetSource); sheet2.close(); } public void processAllSheets(String filename) throws Exception { OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader( pkg ); SharedStringsTable sst = r.getSharedStringsTable(); StylesTable st = r.getStylesTable(); XMLReader parser = fetchSheetParser(sst, st); Iterator sheets = r.getSheetsData(); while(sheets.hasNext()) { System.out.println("Processing new sheet:\n"); InputStream sheet = sheets.next(); InputSource sheetSource = new InputSource(sheet); parser.parse(sheetSource); sheet.close(); System.out.println(""); } } public XMLReader fetchSheetParser(SharedStringsTable sst, StylesTable st) throws SAXException, ParserConfigurationException { /* XMLReader parser = XMLReaderFactory.createXMLReader( "org.apache.xerces.parsers.SAXParser" ); */ XMLReader parser = SAXHelper.newXMLReader(); ContentHandler handler = new SheetHandler(sst, st); parser.setContentHandler(handler); return parser; } /** * See org.xml.sax.helpers.DefaultHandler javadocs */ private static class SheetHandler extends DefaultHandler { private SharedStringsTable sst; private StylesTable st; private String lastContents; private boolean nextIsString; private boolean nextIsStyledNumeric; private boolean inlineStr; private int styleIndex; private DataFormatter formatter; private int rowNumber; private SheetHandler(SharedStringsTable sst, StylesTable st) { this.sst = sst; this.st = st; this.rowNumber = 0; this.formatter = new DataFormatter(java.util.Locale.US, true); this.styleIndex = 0; } public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { // row => row if(name.equals("row")) { if (attributes.getValue("r") != null) { rowNumber = Integer.valueOf(attributes.getValue("r")); } else { rowNumber++; } System.out.println("row: " + rowNumber); } if (rowNumber > 6) { // c => cell if(name.equals("c")) { // Print the cell reference System.out.print(attributes.getValue("r") + " - "); String cellType = attributes.getValue("t"); // Figure out if the value is an index in the SST nextIsString = false; if(cellType != null && cellType.equals("s")) { nextIsString = true; } // Figure out if the value is an inline string inlineStr = false; if(cellType != null && cellType.equals("inlineStr")) { inlineStr = true; } // Figure out if the value is an styled numeric value or date nextIsStyledNumeric = false; if(cellType != null && cellType.equals("n") || cellType == null) { String cellStyle = attributes.getValue("s"); if (cellStyle != null) { styleIndex = Integer.parseInt(cellStyle); nextIsStyledNumeric = true; } } } } // Clear contents cache lastContents = ""; } public void endElement(String uri, String localName, String name) throws SAXException { if (rowNumber > 6) { // Process the last contents as required. // Do now, as characters() may be called more than once // If the value is in the shared string table, get it if(nextIsString) { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); nextIsString = false; } // v => contents of a cell // Output after we've seen the string contents if(name.equals("v") || (inlineStr && name.equals("c"))) { // If the value is styled numeric, use DataFormatter to formaat it if (nextIsStyledNumeric) { XSSFCellStyle style = st.getStyleAt(styleIndex); int formatIndex = style.getDataFormat(); String formatString = style.getDataFormatString(); if (formatString == null) { // formatString could not be found, so it must be a builtin format. formatString = BuiltinFormats.getBuiltinFormat(formatIndex); } double value = Double.valueOf(lastContents); lastContents = formatter.formatRawCellContents(value, formatIndex, formatString); nextIsStyledNumeric = false; } // Print out the contents System.out.println(lastContents); } } } public void characters(char[] ch, int start, int length) throws SAXException { //collect each character part to the content lastContents += new String(ch, start, length); } } public static void main(String[] args) throws Exception { ExampleEventUserModel example = new ExampleEventUserModel(); //example.processOneSheet(args[0]); example.processAllSheets(args[0]); } } 

在我看来,您可以通过与此类似的方式区分您的字符串和Excel:

 private static void checkNumber(String fromExcel) { try { double asNumber = Double.parseDouble(fromExcel); if (asNumber >= 0 && asNumber <= 1) { System.out.println("Percentage: " + asNumber * 100 + " %"); } long asWholeNumber = Math.round(asNumber); try { LocalDate asDate = LocalDate.of(1899, Month.DECEMBER, 30) .plusDays(asWholeNumber); if (asDate.isAfter(LocalDate.of(2000, Month.DECEMBER, 31)) && asDate.isBefore(LocalDate.of(2035, Month.JANUARY, 1))) { System.out.println("Date: " + asDate); } } catch (DateTimeException dte) { System.out.println("Unidentified: " + fromExcel); } } catch (NumberFormatException nfe) { System.out.println("Unidentified: " + fromExcel); } } 

试试这个方法:

  checkNumber("44299"); checkNumber("3.6999999999999998E-2"); 

这打印:

 Date: 2021-04-13 Percentage: 3.6999999999999997 % 

对字符串有两种可能的解释不应该阻止你进行validation并捕获不符合任何一种解释的字符串,所以我尝试对每种情况进行一些过滤。 请注意,如果您在接受日期中包含1899,则“0”和“1”将被接受为日期和百分比。

我正在使用和推荐来自java.time LocalDate ,它是现代Java日期和时间API,用于处理日期。 使用过时的DateGregorianCalendar ,现代API可以更好地工作。

加里'学生想要获得格式化的细胞可能是一种更正确的方法。

问题:我的代码需要与Java 6兼容; 我可以使用java.time吗?

编辑:是的, java.time可以在Java 6中很好地工作。

  • 在Java 8及更高版本和新的Android设备上(从API级别26,我被告知)新的API内置。
  • Java 6和7中获取ThreeTen Backport,这是新类的后端(JST 310的ThreeTen,其中首次描述了现代API)。 编辑2:确保从包org.threeten.bp和子包中导入日期和时间类和exception。
  • 在(较旧的)Android上,使用Android版的ThreeTen Backport。 它被称为ThreeTenABP。 此外,请确保从包org.threeten.bp和子包中导入日期和时间类。

链接

  • Oracle教程:Date Time ,解释了如何使用java.time
  • ThreeTen Backport项目
  • ThreeTenABP ,Android版ThreeTen Backport
  • 问题:如何在Android项目中使用ThreeTenABP ,并给出了非常详尽的解释。
  • Java规范请求(JSR)310 。

此函数包装两种情况(百分比或日期):

 private static String convert(String s) { if(s.indexOf('E') > -1) { // It's a percentage String[] components = s.split("E"); double num = Double.parseDouble(components[0]) * Math.pow(10, Integer.parseInt(components[1])); //return String.valueOf(num); // will return ie "0.037" return Math.round(num * 10000.0) / 100.0 + "%"; // will return ie "3.7%" } else { // It's a date SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); GregorianCalendar gc = new GregorianCalendar(1900, 0, 0); gc.add(Calendar.DATE, Integer.parseInt(s) - 1); Date date = gc.getTime(); return sdf.format(date); } } 

请注意,Excel中的序列号日期表示自1900年1月1日以来经过的天数,因此我使用了转换。

让我知道它对你有用