From 0a0d8a946ae6131a59bcf04f03ce4752fe7ebbcd Mon Sep 17 00:00:00 2001 From: zhuangjiaju Date: Thu, 25 Jul 2019 18:43:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=BB=E5=86=99=E7=9A=84?= =?UTF-8?q?=E5=86=99=E6=B3=95=EF=BC=8C=E6=96=B9=E4=BE=BF=E8=AF=BB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 + .../alibaba/excel/analysis/ExcelExecutor.java | 8 + .../v03/AbstractXlsRecordHandler.java | 4 + .../excel/analysis/v03/XlsRecordHandler.java | 45 + .../excel/analysis/v03/XlsSaxAnalyser.java | 12 +- .../handlers/BlankOrErrorRecordHandler.java | 10 +- ...cordHandler.java => BofRecordHandler.java} | 19 +- .../v03/handlers/FormulaRecordHandler.java | 14 +- .../v03/handlers/LabelRecordHandler.java | 8 +- .../MissingCellDummyRecordHandler.java | 8 +- .../v03/handlers/NoteRecordHandler.java | 9 +- .../v03/handlers/NumberRecordHandler.java | 10 +- ...ecordHandler.java => RkRecordHandler.java} | 10 +- ...cordHandler.java => SstRecordHandler.java} | 13 +- .../v07/SharedStringsTableHandler.java | 1 - .../excel/analysis/v07/XlsxCellHandler.java | 26 +- .../analysis/v07/XlsxRowResultHolder.java | 27 +- .../v07/handlers/CountRowCellHandler.java | 5 + .../v07/handlers/DefaultCellHandler.java | 6 +- .../handlers/ProcessResultCellHandler.java | 5 + .../com/alibaba/excel/cache/ReadCache.java | 6 +- .../excel/context/AnalysisContext.java | 2 + .../alibaba/excel/context/WriteContext.java | 8 +- .../converters/DefaultConverterLoader.java | 4 +- .../alibaba/excel/metadata/IndexValue.java | 39 - .../alibaba/excel/support/ExcelTypeEnum.java | 11 + .../alibaba/excel/util/CollectionUtils.java | 332 +---- .../com/alibaba/excel/util/FileUtils.java | 9 +- .../com/alibaba/excel/util/ObjectUtils.java | 945 ------------ .../com/alibaba/excel/util/StringUtils.java | 1312 +---------------- 30 files changed, 251 insertions(+), 2660 deletions(-) rename src/main/java/com/alibaba/excel/analysis/v03/handlers/{BOFRecordHandler.java => BofRecordHandler.java} (84%) rename src/main/java/com/alibaba/excel/analysis/v03/handlers/{RKRecordHandler.java => RkRecordHandler.java} (84%) rename src/main/java/com/alibaba/excel/analysis/v03/handlers/{SSTRecordHandler.java => SstRecordHandler.java} (79%) delete mode 100644 src/main/java/com/alibaba/excel/metadata/IndexValue.java delete mode 100644 src/main/java/com/alibaba/excel/util/ObjectUtils.java diff --git a/pom.xml b/pom.xml index 3b98672..9ccb242 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,9 @@ rulesets/java/ali-other.xml rulesets/java/ali-set.xml + + com/alibaba/excel/event/AnalysisEventListener.java + diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java b/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java index d9bf156..35bcf4f 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java @@ -11,8 +11,16 @@ import com.alibaba.excel.read.metadata.ReadSheet; */ public interface ExcelExecutor { + /** + * Returns the actual sheet in excel + * + * @return + */ List sheetList(); + /** + * Read sheet + */ void execute(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java index 0aa1335..6e54480 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java @@ -1,5 +1,9 @@ package com.alibaba.excel.analysis.v03; +/** + * + * @author Dan Zheng + */ public abstract class AbstractXlsRecordHandler implements XlsRecordHandler { protected int row = -1; protected int column = -1; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java index 818ab01..08c23d2 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -2,12 +2,57 @@ package com.alibaba.excel.analysis.v03; import org.apache.poi.hssf.record.Record; +/** + * Intercepts handle xls reads. + * + * @author Dan Zheng + */ public interface XlsRecordHandler extends Comparable { + /** + * Which tags are supported + * + * @param record + * @return + */ boolean support(Record record); + + /** + * Initialize + */ void init(); + + /** + * Processing record + * + * @param record + */ void processRecord(Record record); + + /** + * Get row + * + * @return + */ int getRow(); + + /** + * Get column + * + * @return + */ int getColumn(); + + /** + * Get value + * + * @return + */ String getValue(); + + /** + * Get order + * + * @return + */ int getOrder(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index eb232ca..5596c38 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -17,15 +17,15 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import com.alibaba.excel.analysis.ExcelExecutor; -import com.alibaba.excel.analysis.v03.handlers.BOFRecordHandler; import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler; import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler; import com.alibaba.excel.analysis.v03.handlers.MissingCellDummyRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; -import com.alibaba.excel.analysis.v03.handlers.RKRecordHandler; -import com.alibaba.excel.analysis.v03.handlers.SSTRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; @@ -178,13 +178,13 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor { private void buildXlsRecordHandlers() { if (CollectionUtils.isEmpty(recordHandlers)) { recordHandlers.add(new BlankOrErrorRecordHandler()); - recordHandlers.add(new BOFRecordHandler(workbookBuildingListener, analysisContext, sheets)); + recordHandlers.add(new BofRecordHandler(workbookBuildingListener, analysisContext, sheets)); recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener)); recordHandlers.add(new LabelRecordHandler()); recordHandlers.add(new NoteRecordHandler()); recordHandlers.add(new NumberRecordHandler(formatListener)); - recordHandlers.add(new RKRecordHandler()); - recordHandlers.add(new SSTRecordHandler()); + recordHandlers.add(new RkRecordHandler()); + recordHandlers.add(new SstRecordHandler()); recordHandlers.add(new MissingCellDummyRecordHandler()); Collections.sort(recordHandlers); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java index 5f52655..ec95762 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java @@ -1,8 +1,16 @@ package com.alibaba.excel.analysis.v03.handlers; +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.BoolErrRecord; +import org.apache.poi.hssf.record.Record; + import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import org.apache.poi.hssf.record.*; +/** + * Record handler + * + * @author Dan Zheng + */ public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler { @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java similarity index 84% rename from src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java rename to src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index c23cf09..da5967d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -12,16 +12,21 @@ import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.metadata.ReadSheet; -public class BOFRecordHandler extends AbstractXlsRecordHandler { +/** + * Record handler + * + * @author Dan Zheng + */ +public class BofRecordHandler extends AbstractXlsRecordHandler { private List boundSheetRecords = new ArrayList(); - private BoundSheetRecord[] orderedBSRs; + private BoundSheetRecord[] orderedBsrs; private int sheetIndex; private List sheets; private AnalysisContext context; private boolean analyAllSheet; private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; - public BOFRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, + public BofRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, AnalysisContext context, List sheets) { this.context = context; this.workbookBuildingListener = workbookBuildingListener; @@ -40,11 +45,11 @@ public class BOFRecordHandler extends AbstractXlsRecordHandler { } else if (record.getSid() == BOFRecord.sid) { BOFRecord br = (BOFRecord)record; if (br.getType() == BOFRecord.TYPE_WORKSHEET) { - if (orderedBSRs == null) { - orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); + if (orderedBsrs == null) { + orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); } sheetIndex++; - ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBSRs[sheetIndex - 1].getSheetname()); + ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBsrs[sheetIndex - 1].getSheetname()); sheets.add(readSheet); if (this.analyAllSheet) { context.currentSheet(null, readSheet); @@ -59,7 +64,7 @@ public class BOFRecordHandler extends AbstractXlsRecordHandler { this.analyAllSheet = true; } sheetIndex = 0; - orderedBSRs = null; + orderedBsrs = null; boundSheetRecords.clear(); sheets.clear(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index fddfd64..0cb33f5 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -1,11 +1,19 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ public class FormulaRecordHandler extends AbstractXlsRecordHandler { private int nextRow; private int nextColumn; @@ -16,10 +24,12 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler { private boolean outputNextStringRecord; private FormatTrackingHSSFListener formatListener; private HSSFWorkbook stubWorkbook; + public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) { this.stubWorkbook = stubWorkbook; this.formatListener = formatListener; } + @Override public boolean support(Record record) { return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java index c342e40..519c91e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -1,9 +1,15 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.Record; +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ public class LabelRecordHandler extends AbstractXlsRecordHandler { @Override public boolean support(Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java index ad97aba..e90f9bb 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java @@ -1,9 +1,15 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.record.Record; +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler { @Override public boolean support(Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java index 8704f4b..4acef12 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -1,9 +1,15 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.Record; +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ public class NoteRecordHandler extends AbstractXlsRecordHandler { @Override public boolean support(Record record) { @@ -16,7 +22,6 @@ public class NoteRecordHandler extends AbstractXlsRecordHandler { this.row = nrec.getRow(); this.column = nrec.getColumn(); - // TODO: Find object to match nrec.getShapeId() this.value = "(TODO)"; } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index a87a56b..b0eddc6 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -1,15 +1,23 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.Record; +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ public class NumberRecordHandler extends AbstractXlsRecordHandler { private FormatTrackingHSSFListener formatListener; + public NumberRecordHandler(FormatTrackingHSSFListener formatListener) { this.formatListener = formatListener; } + @Override public boolean support(Record record) { return NumberRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java similarity index 84% rename from src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java rename to src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java index 5f4b9ce..028ec69 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -1,10 +1,16 @@ package com.alibaba.excel.analysis.v03.handlers; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; -public class RKRecordHandler extends AbstractXlsRecordHandler { +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class RkRecordHandler extends AbstractXlsRecordHandler { @Override public boolean support(Record record) { return RKRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java similarity index 79% rename from src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java rename to src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java index 841686b..027bf81 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -1,10 +1,19 @@ package com.alibaba.excel.analysis.v03.handlers; +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SSTRecord; + import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import org.apache.poi.hssf.record.*; -public class SSTRecordHandler extends AbstractXlsRecordHandler { +/** + * Record handler + * + * @author Dan Zheng + */ +public class SstRecordHandler extends AbstractXlsRecordHandler { private SSTRecord sstRecord; + @Override public boolean support(Record record) { return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java index f6a8d30..bb4d1a7 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java @@ -12,7 +12,6 @@ import com.alibaba.excel.cache.ReadCache; public class SharedStringsTableHandler extends DefaultHandler { private static final String T_TAG = "t"; private String currentData; - private boolean isT; private ReadCache readCache; public SharedStringsTableHandler(ReadCache readCache) { diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java index dfc0fe8..831a986 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java @@ -2,10 +2,32 @@ package com.alibaba.excel.analysis.v07; import org.xml.sax.Attributes; +/** + * Cell handler + * + * @author Dan Zheng + */ public interface XlsxCellHandler { + /** + * Which tags are supported + * + * @param name + * @return + */ boolean support(String name); - + + /** + * Start handle + * + * @param name + * @param attributes + */ void startHandle(String name, Attributes attributes); - + + /** + * End handle + * + * @param name + */ void endHandle(String name); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java index 6269b3b..2867e74 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java @@ -2,12 +2,35 @@ package com.alibaba.excel.analysis.v07; import com.alibaba.excel.metadata.CellData; +/** + * Result holder + * + * @author jipengfei + */ public interface XlsxRowResultHolder { + /** + * Clear Result + */ void clearResult(); - + + /** + * Append current 'cellValue' + * + * @param currentCellValue + */ void appendCurrentCellValue(String currentCellValue); + /** + * Get row content + * + * @return + */ CellData[] getCurRowContent(); - + + /** + * get column size + * + * @return + */ int getColumnSize(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java index f4afdeb..ea63409 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java @@ -8,6 +8,11 @@ import org.xml.sax.Attributes; import com.alibaba.excel.analysis.v07.XlsxCellHandler; import com.alibaba.excel.context.AnalysisContext; +/** + * Cell Handler + * + * @author jipengfei + */ public class CountRowCellHandler implements XlsxCellHandler { private final AnalysisContext analysisContext; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index 7e8d2f3..2319f67 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -21,7 +21,11 @@ import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.util.BooleanUtils; import com.alibaba.excel.util.PositionUtils; import com.alibaba.excel.util.StringUtils; - +/** + * Cell Handler + * + * @author jipengfei + */ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder { private final AnalysisContext analysisContext; private String currentTag; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java index dc175e0..4040cb4 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -9,6 +9,11 @@ import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; +/** + * Cell Handler + * + * @author jipengfei + */ public class ProcessResultCellHandler implements XlsxCellHandler { private AnalysisContext analysisContext; private XlsxRowResultHolder rowResultHandler; diff --git a/src/main/java/com/alibaba/excel/cache/ReadCache.java b/src/main/java/com/alibaba/excel/cache/ReadCache.java index e31f7c2..45a3490 100644 --- a/src/main/java/com/alibaba/excel/cache/ReadCache.java +++ b/src/main/java/com/alibaba/excel/cache/ReadCache.java @@ -24,7 +24,7 @@ public interface ReadCache { void put(String value); /** - * Get + * Get value * * @param key * @return @@ -32,12 +32,12 @@ public interface ReadCache { String get(Integer key); /** - * 所有 + * It's called when all the values are put in */ void putFinished(); /** - * + * Called when the excel read is complete */ void destroy(); diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index bcd71e6..2704bfd 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -64,6 +64,8 @@ public interface AnalysisContext { /** * Custom attribute + * + * @return */ Object getCustom(); diff --git a/src/main/java/com/alibaba/excel/context/WriteContext.java b/src/main/java/com/alibaba/excel/context/WriteContext.java index 8680277..3ee97d1 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContext.java +++ b/src/main/java/com/alibaba/excel/context/WriteContext.java @@ -67,6 +67,7 @@ public interface WriteContext { void finish(); /** + * Current sheet * * @return * @deprecated please us e{@link #writeSheetHolder()} @@ -75,6 +76,7 @@ public interface WriteContext { Sheet getCurrentSheet(); /** + * Need head * * @return * @deprecated please us e{@link #writeSheetHolder()} @@ -83,7 +85,8 @@ public interface WriteContext { boolean needHead(); /** - * + * Get outputStream + * * @return * @deprecated please us e{@link #writeWorkbookHolder()} ()} */ @@ -91,7 +94,8 @@ public interface WriteContext { OutputStream getOutputStream(); /** - * + * Get workbook + * * @return * @deprecated please us e{@link #writeWorkbookHolder()} ()} */ diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java index 8c6748e..7a6519e 100644 --- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java +++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java @@ -40,7 +40,7 @@ public class DefaultConverterLoader { * @return */ public static Map loadDefaultWriteConverter() { - Map converterMap = new HashMap(); + Map converterMap = new HashMap(16); putWriteConverter(converterMap, new BigDecimalNumberConverter()); putWriteConverter(converterMap, new BooleanBooleanConverter()); putWriteConverter(converterMap, new ByteNumberConverter()); @@ -64,7 +64,7 @@ public class DefaultConverterLoader { * @return */ public static Map loadDefaultReadConverter() { - Map converterMap = new HashMap(); + Map converterMap = new HashMap(64); putReadConverter(converterMap, new BigDecimalBooleanConverter()); putReadConverter(converterMap, new BigDecimalNumberConverter()); putReadConverter(converterMap, new BigDecimalStringConverter()); diff --git a/src/main/java/com/alibaba/excel/metadata/IndexValue.java b/src/main/java/com/alibaba/excel/metadata/IndexValue.java deleted file mode 100644 index 2be0427..0000000 --- a/src/main/java/com/alibaba/excel/metadata/IndexValue.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.alibaba.excel.metadata; - -/** - * @author jipengfei - */ -public class IndexValue { - - private String v_index; - private String v_value; - - public IndexValue(String v_index, String v_value) { - super(); - this.v_index = v_index; - this.v_value = v_value; - } - - public String getV_index() { - return v_index; - } - - public void setV_index(String v_index) { - this.v_index = v_index; - } - - public String getV_value() { - return v_value; - } - - public void setV_value(String v_value) { - this.v_value = v_value; - } - - @Override - public String toString() { - return "IndexValue [v_index=" + v_index + ", v_value=" + v_value + "]"; - } - - -} diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java index 9aec2ed..4bbda76 100644 --- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -32,6 +32,17 @@ public enum ExcelTypeEnum { FileMagic fileMagic = null; if (file != null) { fileMagic = FileMagic.valueOf(file); + if (!FileMagic.OLE2.equals(fileMagic) && !FileMagic.OOXML.equals(fileMagic)) { + String fileName = file.getName(); + if (fileName.endsWith(XLSX.getValue())) { + return XLSX; + + } else if (fileName.endsWith(XLS.getValue())) { + return XLS; + } else { + throw new ExcelCommonException("Unknown excel type."); + } + } } else { fileMagic = FileMagic.valueOf(inputStream); } diff --git a/src/main/java/com/alibaba/excel/util/CollectionUtils.java b/src/main/java/com/alibaba/excel/util/CollectionUtils.java index 3b9025f..fff57ff 100644 --- a/src/main/java/com/alibaba/excel/util/CollectionUtils.java +++ b/src/main/java/com/alibaba/excel/util/CollectionUtils.java @@ -1,340 +1,20 @@ package com.alibaba.excel.util; -import java.util.*; +import java.util.Collection; +import java.util.Map; /** - * Miscellaneous collection utility methods. - * Mainly for internal use within the framework. - * - * @author Juergen Hoeller - * @author Rob Harrop - * @author Arjen Poutsma - * @since 1.1.3 + * Collection utils + * + * @author jipengfei */ -public abstract class CollectionUtils { +public class CollectionUtils { - /** - * Return {@code true} if the supplied Collection is {@code null} or empty. - * Otherwise, return {@code false}. - * @param collection the Collection to check - * @return whether the given Collection is empty - */ public static boolean isEmpty(Collection collection) { return (collection == null || collection.isEmpty()); } - /** - * Return {@code true} if the supplied Map is {@code null} or empty. - * Otherwise, return {@code false}. - * @param map the Map to check - * @return whether the given Map is empty - */ public static boolean isEmpty(Map map) { return (map == null || map.isEmpty()); } - - /** - * Convert the supplied array into a List. A primitive array gets converted - * into a List of the appropriate wrapper type. - *

NOTE: Generally prefer the standard {@link Arrays#asList} method. - * This {@code arrayToList} method is just meant to deal with an incoming Object - * value that might be an {@code Object[]} or a primitive array at runtime. - *

A {@code null} source value will be converted to an empty List. - * @param source the (potentially primitive) array - * @return the converted List result - * @see ObjectUtils#toObjectArray(Object) - * @see Arrays#asList(Object[]) - */ - @SuppressWarnings("rawtypes") - public static List arrayToList(Object source) { - return Arrays.asList(ObjectUtils.toObjectArray(source)); - } - - /** - * Merge the given array into the given Collection. - * @param array the array to merge (may be {@code null}) - * @param collection the target Collection to merge the array into - */ - @SuppressWarnings("unchecked") - public static void mergeArrayIntoCollection(Object array, Collection collection) { - if (collection == null) { - throw new IllegalArgumentException("Collection must not be null"); - } - Object[] arr = ObjectUtils.toObjectArray(array); - for (Object elem : arr) { - collection.add((E) elem); - } - } - - /** - * Merge the given Properties instance into the given Map, - * copying all properties (key-value pairs) over. - *

Uses {@code Properties.propertyNames()} to even catch - * default properties linked into the original Properties instance. - * @param props the Properties instance to merge (may be {@code null}) - * @param map the target Map to merge the properties into - */ - @SuppressWarnings("unchecked") - public static void mergePropertiesIntoMap(Properties props, Map map) { - if (map == null) { - throw new IllegalArgumentException("Map must not be null"); - } - if (props != null) { - for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { - String key = (String) en.nextElement(); - Object value = props.get(key); - if (value == null) { - // Allow for defaults fallback or potentially overridden accessor... - value = props.getProperty(key); - } - map.put((K) key, (V) value); - } - } - } - - - /** - * Check whether the given Iterator contains the given element. - * @param iterator the Iterator to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean contains(Iterator iterator, Object element) { - if (iterator != null) { - while (iterator.hasNext()) { - Object candidate = iterator.next(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Enumeration contains the given element. - * @param enumeration the Enumeration to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean contains(Enumeration enumeration, Object element) { - if (enumeration != null) { - while (enumeration.hasMoreElements()) { - Object candidate = enumeration.nextElement(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Collection contains the given element instance. - *

Enforces the given instance to be present, rather than returning - * {@code true} for an equal element as well. - * @param collection the Collection to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean containsInstance(Collection collection, Object element) { - if (collection != null) { - for (Object candidate : collection) { - if (candidate == element) { - return true; - } - } - } - return false; - } - - /** - * Return {@code true} if any element in '{@code candidates}' is - * contained in '{@code source}'; otherwise returns {@code false}. - * @param source the source Collection - * @param candidates the candidates to search for - * @return whether any of the candidates has been found - */ - public static boolean containsAny(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return false; - } - for (Object candidate : candidates) { - if (source.contains(candidate)) { - return true; - } - } - return false; - } - - /** - * Return the first element in '{@code candidates}' that is contained in - * '{@code source}'. If no element in '{@code candidates}' is present in - * '{@code source}' returns {@code null}. Iteration order is - * {@link Collection} implementation specific. - * @param source the source Collection - * @param candidates the candidates to search for - * @return the first present object, or {@code null} if not found - */ - @SuppressWarnings("unchecked") - public static E findFirstMatch(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return null; - } - for (Object candidate : candidates) { - if (source.contains(candidate)) { - return (E) candidate; - } - } - return null; - } - - /** - * Find a single value of the given type in the given Collection. - * @param collection the Collection to search - * @param type the type to look for - * @return a value of the given type found if there is a clear match, - * or {@code null} if none or more than one such value found - */ - @SuppressWarnings("unchecked") - public static T findValueOfType(Collection collection, Class type) { - if (isEmpty(collection)) { - return null; - } - T value = null; - for (Object element : collection) { - if (type == null || type.isInstance(element)) { - if (value != null) { - // More than one value found... no clear single value. - return null; - } - value = (T) element; - } - } - return value; - } - - /** - * Find a single value of one of the given types in the given Collection: - * searching the Collection for a value of the first type, then - * searching for a value of the second type, etc. - * @param collection the collection to search - * @param types the types to look for, in prioritized order - * @return a value of one of the given types found if there is a clear match, - * or {@code null} if none or more than one such value found - */ - public static Object findValueOfType(Collection collection, Class[] types) { - if (isEmpty(collection) || ObjectUtils.isEmpty(types)) { - return null; - } - for (Class type : types) { - Object value = findValueOfType(collection, type); - if (value != null) { - return value; - } - } - return null; - } - - /** - * Determine whether the given Collection only contains a single unique object. - * @param collection the Collection to check - * @return {@code true} if the collection contains a single reference or - * multiple references to the same instance, {@code false} else - */ - public static boolean hasUniqueObject(Collection collection) { - if (isEmpty(collection)) { - return false; - } - boolean hasCandidate = false; - Object candidate = null; - for (Object elem : collection) { - if (!hasCandidate) { - hasCandidate = true; - candidate = elem; - } - else if (candidate != elem) { - return false; - } - } - return true; - } - - /** - * Find the common element type of the given Collection, if any. - * @param collection the Collection to check - * @return the common element type, or {@code null} if no clear - * common type has been found (or the collection was empty) - */ - public static Class findCommonElementType(Collection collection) { - if (isEmpty(collection)) { - return null; - } - Class candidate = null; - for (Object val : collection) { - if (val != null) { - if (candidate == null) { - candidate = val.getClass(); - } - else if (candidate != val.getClass()) { - return null; - } - } - } - return candidate; - } - - /** - * Marshal the elements from the given enumeration into an array of the given type. - * Enumeration elements must be assignable to the type of the given array. The array - * returned will be a different instance than the array given. - */ - public static A[] toArray(Enumeration enumeration, A[] array) { - ArrayList elements = new ArrayList(); - while (enumeration.hasMoreElements()) { - elements.add(enumeration.nextElement()); - } - return elements.toArray(array); - } - - /** - * Adapt an enumeration to an iterator. - * @param enumeration the enumeration - * @return the iterator - */ - public static Iterator toIterator(Enumeration enumeration) { - return new EnumerationIterator(enumeration); - } - - - - /** - * Iterator wrapping an Enumeration. - */ - private static class EnumerationIterator implements Iterator { - - private final Enumeration enumeration; - - public EnumerationIterator(Enumeration enumeration) { - this.enumeration = enumeration; - } - - @Override - public boolean hasNext() { - return this.enumeration.hasMoreElements(); - } - - @Override - public E next() { - return this.enumeration.nextElement(); - } - - @Override - public void remove() throws UnsupportedOperationException { - throw new UnsupportedOperationException("Not supported"); - } - } - - } - diff --git a/src/main/java/com/alibaba/excel/util/FileUtils.java b/src/main/java/com/alibaba/excel/util/FileUtils.java index e6a4554..52353d1 100644 --- a/src/main/java/com/alibaba/excel/util/FileUtils.java +++ b/src/main/java/com/alibaba/excel/util/FileUtils.java @@ -20,6 +20,7 @@ public class FileUtils { private static final String POIFILES = "poifiles"; private static final String CACHE = "excache"; + private static final int WRITE_BUFF_SIZE = 8192; /** * Write inputStream to file @@ -32,8 +33,8 @@ public class FileUtils { try { outputStream = new FileOutputStream(file); int bytesRead; - byte[] buffer = new byte[8192]; - while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) { + byte[] buffer = new byte[WRITE_BUFF_SIZE]; + while ((bytesRead = inputStream.read(buffer, 0, WRITE_BUFF_SIZE)) != -1) { outputStream.write(buffer, 0, bytesRead); } } catch (Exception e) { @@ -98,7 +99,7 @@ public class FileUtils { } File directory = new File(tmpDir, path); if (!directory.exists()) { - syncCreatePOIFilesDirectory(directory); + syncCreatePoiFilesDirectory(directory); } return directory; } @@ -107,7 +108,7 @@ public class FileUtils { * * @param directory */ - private static synchronized void syncCreatePOIFilesDirectory(File directory) { + private static synchronized void syncCreatePoiFilesDirectory(File directory) { if (!directory.exists()) { directory.mkdirs(); } diff --git a/src/main/java/com/alibaba/excel/util/ObjectUtils.java b/src/main/java/com/alibaba/excel/util/ObjectUtils.java deleted file mode 100644 index 8b8556c..0000000 --- a/src/main/java/com/alibaba/excel/util/ObjectUtils.java +++ /dev/null @@ -1,945 +0,0 @@ -package com.alibaba.excel.util; - -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; - -/** - * Miscellaneous object utility methods. - * - *

Mainly for internal use within the framework. - * - *

Thanks to Alex Ruiz for contributing several enhancements to this class! - * - * @author Juergen Hoeller - * @author Keith Donald - * @author Rod Johnson - * @author Rob Harrop - * @author Chris Beams - * @author Sam Brannen - * @since 19.03.2004 - * @see CollectionUtils - */ -public abstract class ObjectUtils { - - private static final int INITIAL_HASH = 7; - private static final int MULTIPLIER = 31; - - private static final String EMPTY_STRING = ""; - private static final String NULL_STRING = "null"; - private static final String ARRAY_START = "{"; - private static final String ARRAY_END = "}"; - private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; - private static final String ARRAY_ELEMENT_SEPARATOR = ", "; - - - /** - * Return whether the given throwable is a checked exception: - * that is, neither a RuntimeException nor an Error. - * @param ex the throwable to check - * @return whether the throwable is a checked exception - * @see Exception - * @see RuntimeException - * @see Error - */ - public static boolean isCheckedException(Throwable ex) { - return !(ex instanceof RuntimeException || ex instanceof Error); - } - - /** - * Check whether the given exception is compatible with the specified - * exception types, as declared in a throws clause. - * @param ex the exception to check - * @param declaredExceptions the exception types declared in the throws clause - * @return whether the given exception is compatible - */ - public static boolean isCompatibleWithThrowsClause(Throwable ex, Class... declaredExceptions) { - if (!isCheckedException(ex)) { - return true; - } - if (declaredExceptions != null) { - for (Class declaredException : declaredExceptions) { - if (declaredException.isInstance(ex)) { - return true; - } - } - } - return false; - } - - /** - * Determine whether the given object is an array: - * either an Object array or a primitive array. - * @param obj the object to check - */ - public static boolean isArray(Object obj) { - return (obj != null && obj.getClass().isArray()); - } - - /** - * Determine whether the given array is empty: - * i.e. {@code null} or of zero length. - * @param array the array to check - * @see #isEmpty(Object) - */ - public static boolean isEmpty(Object[] array) { - return (array == null || array.length == 0); - } - - /** - * Determine whether the given object is empty. - *

This method supports the following object types. - *

- *

If the given object is non-null and not one of the aforementioned - * supported types, this method returns {@code false}. - * @param obj the object to check - * @return {@code true} if the object is {@code null} or empty - * @since 4.2 - * @see ObjectUtils#isEmpty(Object[]) - * @see StringUtils#hasLength(CharSequence) - * @see StringUtils#isEmpty(Object) - * @see CollectionUtils#isEmpty(Collection) - * @see CollectionUtils#isEmpty(Map) - */ - @SuppressWarnings("rawtypes") - public static boolean isEmpty(Object obj) { - if (obj == null) { - return true; - } - - if (obj instanceof CharSequence) { - return ((CharSequence) obj).length() == 0; - } - if (obj.getClass().isArray()) { - return Array.getLength(obj) == 0; - } - if (obj instanceof Collection) { - return ((Collection) obj).isEmpty(); - } - if (obj instanceof Map) { - return ((Map) obj).isEmpty(); - } - - // else - return false; - } - - /** - * Check whether the given array contains the given element. - * @param array the array to check (may be {@code null}, - * in which case the return value will always be {@code false}) - * @param element the element to check for - * @return whether the element has been found in the given array - */ - public static boolean containsElement(Object[] array, Object element) { - if (array == null) { - return false; - } - for (Object arrayEle : array) { - if (nullSafeEquals(arrayEle, element)) { - return true; - } - } - return false; - } - - /** - * Check whether the given array of enum constants contains a constant with the given name, - * ignoring case when determining a match. - * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() - * @param constant the constant name to find (must not be null or empty string) - * @return whether the constant has been found in the given array - */ - public static boolean containsConstant(Enum[] enumValues, String constant) { - return containsConstant(enumValues, constant, false); - } - - /** - * Check whether the given array of enum constants contains a constant with the given name. - * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() - * @param constant the constant name to find (must not be null or empty string) - * @param caseSensitive whether case is significant in determining a match - * @return whether the constant has been found in the given array - */ - public static boolean containsConstant(Enum[] enumValues, String constant, boolean caseSensitive) { - for (Enum candidate : enumValues) { - if (caseSensitive ? - candidate.toString().equals(constant) : - candidate.toString().equalsIgnoreCase(constant)) { - return true; - } - } - return false; - } - - /** - * Case insensitive alternative to {@link Enum#valueOf(Class, String)}. - * @param the concrete Enum type - * @param enumValues the array of all Enum constants in question, usually per Enum.values() - * @param constant the constant to get the enum value of - * @throws IllegalArgumentException if the given constant is not found in the given array - * of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to avoid this exception. - */ - public static > E caseInsensitiveValueOf(E[] enumValues, String constant) { - for (E candidate : enumValues) { - if (candidate.toString().equalsIgnoreCase(constant)) { - return candidate; - } - } - throw new IllegalArgumentException( - String.format("constant [%s] does not exist in enum type %s", - constant, enumValues.getClass().getComponentType().getName())); - } - - /** - * Append the given object to the given array, returning a new array - * consisting of the input array contents plus the given object. - * @param array the array to append to (can be {@code null}) - * @param obj the object to append - * @return the new array (of the same component type; never {@code null}) - */ - public static A[] addObjectToArray(A[] array, O obj) { - Class compType = Object.class; - if (array != null) { - compType = array.getClass().getComponentType(); - } - else if (obj != null) { - compType = obj.getClass(); - } - int newArrLength = (array != null ? array.length + 1 : 1); - @SuppressWarnings("unchecked") - A[] newArr = (A[]) Array.newInstance(compType, newArrLength); - if (array != null) { - System.arraycopy(array, 0, newArr, 0, array.length); - } - newArr[newArr.length - 1] = obj; - return newArr; - } - - /** - * Convert the given array (which may be a primitive array) to an - * object array (if necessary of primitive wrapper objects). - *

A {@code null} source value will be converted to an - * empty Object array. - * @param source the (potentially primitive) array - * @return the corresponding object array (never {@code null}) - * @throws IllegalArgumentException if the parameter is not an array - */ - public static Object[] toObjectArray(Object source) { - if (source instanceof Object[]) { - return (Object[]) source; - } - if (source == null) { - return new Object[0]; - } - if (!source.getClass().isArray()) { - throw new IllegalArgumentException("Source is not an array: " + source); - } - int length = Array.getLength(source); - if (length == 0) { - return new Object[0]; - } - Class wrapperType = Array.get(source, 0).getClass(); - Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); - for (int i = 0; i < length; i++) { - newArray[i] = Array.get(source, i); - } - return newArray; - } - - - //--------------------------------------------------------------------- - // Convenience methods for content-based equality/hash-code handling - //--------------------------------------------------------------------- - - /** - * Determine if the given objects are equal, returning {@code true} if - * both are {@code null} or {@code false} if only one is {@code null}. - *

Compares arrays with {@code Arrays.equals}, performing an equality - * check based on the array elements rather than the array reference. - * @param o1 first Object to compare - * @param o2 second Object to compare - * @return whether the given objects are equal - * @see Object#equals(Object) - * @see Arrays#equals - */ - public static boolean nullSafeEquals(Object o1, Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } - if (o1.equals(o2)) { - return true; - } - if (o1.getClass().isArray() && o2.getClass().isArray()) { - return arrayEquals(o1, o2); - } - return false; - } - - /** - * Compare the given arrays with {@code Arrays.equals}, performing an equality - * check based on the array elements rather than the array reference. - * @param o1 first array to compare - * @param o2 second array to compare - * @return whether the given objects are equal - * @see #nullSafeEquals(Object, Object) - * @see Arrays#equals - */ - private static boolean arrayEquals(Object o1, Object o2) { - if (o1 instanceof Object[] && o2 instanceof Object[]) { - return Arrays.equals((Object[]) o1, (Object[]) o2); - } - if (o1 instanceof boolean[] && o2 instanceof boolean[]) { - return Arrays.equals((boolean[]) o1, (boolean[]) o2); - } - if (o1 instanceof byte[] && o2 instanceof byte[]) { - return Arrays.equals((byte[]) o1, (byte[]) o2); - } - if (o1 instanceof char[] && o2 instanceof char[]) { - return Arrays.equals((char[]) o1, (char[]) o2); - } - if (o1 instanceof double[] && o2 instanceof double[]) { - return Arrays.equals((double[]) o1, (double[]) o2); - } - if (o1 instanceof float[] && o2 instanceof float[]) { - return Arrays.equals((float[]) o1, (float[]) o2); - } - if (o1 instanceof int[] && o2 instanceof int[]) { - return Arrays.equals((int[]) o1, (int[]) o2); - } - if (o1 instanceof long[] && o2 instanceof long[]) { - return Arrays.equals((long[]) o1, (long[]) o2); - } - if (o1 instanceof short[] && o2 instanceof short[]) { - return Arrays.equals((short[]) o1, (short[]) o2); - } - return false; - } - - /** - * Return as hash code for the given object; typically the value of - * {@code Object#hashCode()}}. If the object is an array, - * this method will delegate to any of the {@code nullSafeHashCode} - * methods for arrays in this class. If the object is {@code null}, - * this method returns 0. - * @see Object#hashCode() - * @see #nullSafeHashCode(Object[]) - * @see #nullSafeHashCode(boolean[]) - * @see #nullSafeHashCode(byte[]) - * @see #nullSafeHashCode(char[]) - * @see #nullSafeHashCode(double[]) - * @see #nullSafeHashCode(float[]) - * @see #nullSafeHashCode(int[]) - * @see #nullSafeHashCode(long[]) - * @see #nullSafeHashCode(short[]) - */ - public static int nullSafeHashCode(Object obj) { - if (obj == null) { - return 0; - } - if (obj.getClass().isArray()) { - if (obj instanceof Object[]) { - return nullSafeHashCode((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeHashCode((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeHashCode((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeHashCode((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeHashCode((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeHashCode((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeHashCode((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeHashCode((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeHashCode((short[]) obj); - } - } - return obj.hashCode(); - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(Object[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (Object element : array) { - hash = MULTIPLIER * hash + nullSafeHashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(boolean[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (boolean element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(byte[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (byte element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(char[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (char element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(double[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (double element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(float[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (float element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(int[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (int element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(long[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (long element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(short[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (short element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return the same value as {@link Boolean#hashCode()}}. - * @see Boolean#hashCode() - */ - public static int hashCode(boolean bool) { - return (bool ? 1231 : 1237); - } - - /** - * Return the same value as {@link Double#hashCode()}}. - * @see Double#hashCode() - */ - public static int hashCode(double dbl) { - return hashCode(Double.doubleToLongBits(dbl)); - } - - /** - * Return the same value as {@link Float#hashCode()}}. - * @see Float#hashCode() - */ - public static int hashCode(float flt) { - return Float.floatToIntBits(flt); - } - - /** - * Return the same value as {@link Long#hashCode()}}. - * @see Long#hashCode() - */ - public static int hashCode(long lng) { - return (int) (lng ^ (lng >>> 32)); - } - - - //--------------------------------------------------------------------- - // Convenience methods for toString output - //--------------------------------------------------------------------- - - /** - * Return a String representation of an object's overall identity. - * @param obj the object (may be {@code null}) - * @return the object's identity as String representation, - * or an empty String if the object was {@code null} - */ - public static String identityToString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return obj.getClass().getName() + "@" + getIdentityHexString(obj); - } - - /** - * Return a hex String form of an object's identity hash code. - * @param obj the object - * @return the object's identity code in hex notation - */ - public static String getIdentityHexString(Object obj) { - return Integer.toHexString(System.identityHashCode(obj)); - } - - /** - * Return a content-based String representation if {@code obj} is - * not {@code null}; otherwise returns an empty String. - *

Differs from {@link #nullSafeToString(Object)} in that it returns - * an empty String rather than "null" for a {@code null} value. - * @param obj the object to build a display String for - * @return a display String representation of {@code obj} - * @see #nullSafeToString(Object) - */ - public static String getDisplayString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return nullSafeToString(obj); - } - - /** - * Determine the class name for the given object. - *

Returns {@code "null"} if {@code obj} is {@code null}. - * @param obj the object to introspect (may be {@code null}) - * @return the corresponding class name - */ - public static String nullSafeClassName(Object obj) { - return (obj != null ? obj.getClass().getName() : NULL_STRING); - } - - /** - * Return a String representation of the specified Object. - *

Builds a String representation of the contents in case of an array. - * Returns {@code "null"} if {@code obj} is {@code null}. - * @param obj the object to build a String representation for - * @return a String representation of {@code obj} - */ - public static String nullSafeToString(Object obj) { - if (obj == null) { - return NULL_STRING; - } - if (obj instanceof String) { - return (String) obj; - } - if (obj instanceof Object[]) { - return nullSafeToString((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeToString((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeToString((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeToString((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeToString((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeToString((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeToString((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeToString((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeToString((short[]) obj); - } - String str = obj.toString(); - return (str != null ? str : EMPTY_STRING); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(Object[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(String.valueOf(array[i])); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(boolean[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(byte[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(char[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append("'").append(array[i]).append("'"); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(double[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(float[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(int[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(long[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(short[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - -} diff --git a/src/main/java/com/alibaba/excel/util/StringUtils.java b/src/main/java/com/alibaba/excel/util/StringUtils.java index b4a5898..8210a19 100644 --- a/src/main/java/com/alibaba/excel/util/StringUtils.java +++ b/src/main/java/com/alibaba/excel/util/StringUtils.java @@ -1,1317 +1,13 @@ package com.alibaba.excel.util; -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TimeZone; -import java.util.UUID; - -import org.apache.commons.codec.binary.CharSequenceUtils; - /** - * Miscellaneous {@link String} utility methods. - * - *

Mainly for internal use within the framework; consider - * Apache's Commons Lang - * for a more comprehensive suite of {@code String} utilities. - * - *

This class delivers some simple functionality that should really be - * provided by the core Java {@link String} and {@link StringBuilder} - * classes. It also provides easy-to-use methods to convert between - * delimited strings, such as CSV strings, and collections and arrays. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Keith Donald - * @author Rob Harrop - * @author Rick Evans - * @author Arjen Poutsma - * @author Sam Brannen - * @author Brian Clozel - * @since 16 April 2001 + * String utils + * + * @author jipengfei */ -public abstract class StringUtils { - - private static final String FOLDER_SEPARATOR = "/"; - - private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; - - private static final String TOP_PATH = ".."; - - private static final String CURRENT_PATH = "."; - - private static final char EXTENSION_SEPARATOR = '.'; - - - //--------------------------------------------------------------------- - // General convenience methods for working with Strings - //--------------------------------------------------------------------- +public class StringUtils { - /** - * Check whether the given {@code String} is empty. - *

This method accepts any Object as an argument, comparing it to - * {@code null} and the empty String. As a consequence, this method - * will never return {@code true} for a non-null non-String object. - *

The Object signature is useful for general attribute handling code - * that commonly deals with Strings but generally has to iterate over - * Objects since attributes may e.g. be primitive value objects as well. - * @param str the candidate String - * @since 3.2.1 - */ public static boolean isEmpty(Object str) { return (str == null || "".equals(str)); } - - /** - * Check that the given {@code CharSequence} is neither {@code null} nor - * of length 0. - *

Note: this method returns {@code true} for a {@code CharSequence} - * that purely consists of whitespace. - *

-     * StringUtils.hasLength(null) = false
-     * StringUtils.hasLength("") = false
-     * StringUtils.hasLength(" ") = true
-     * StringUtils.hasLength("Hello") = true
-     * 
- * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not {@code null} and has length - * @see #hasText(String) - */ - public static boolean hasLength(CharSequence str) { - return (str != null && str.length() > 0); - } - - /** - * Check that the given {@code String} is neither {@code null} nor of length 0. - *

Note: this method returns {@code true} for a {@code String} that - * purely consists of whitespace. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not {@code null} and has length - * @see #hasLength(CharSequence) - * @see #hasText(String) - */ - public static boolean hasLength(String str) { - return (str != null && !str.isEmpty()); - } - - /** - * Check whether the given {@code CharSequence} contains actual text. - *

More specifically, this method returns {@code true} if the - * {@code CharSequence} is not {@code null}, its length is greater than - * 0, and it contains at least one non-whitespace character. - *

-     * StringUtils.hasText(null) = false
-     * StringUtils.hasText("") = false
-     * StringUtils.hasText(" ") = false
-     * StringUtils.hasText("12345") = true
-     * StringUtils.hasText(" 12345 ") = true
-     * 
- * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not {@code null}, - * its length is greater than 0, and it does not contain whitespace only - * @see Character#isWhitespace - */ - public static boolean hasText(CharSequence str) { - return (hasLength(str) && containsText(str)); - } - - /** - * Check whether the given {@code String} contains actual text. - *

More specifically, this method returns {@code true} if the - * {@code String} is not {@code null}, its length is greater than 0, - * and it contains at least one non-whitespace character. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not {@code null}, its - * length is greater than 0, and it does not contain whitespace only - * @see #hasText(CharSequence) - */ - public static boolean hasText(String str) { - return (hasLength(str) && containsText(str)); - } - - private static boolean containsText(CharSequence str) { - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (!Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given {@code CharSequence} contains any whitespace characters. - * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not empty and - * contains at least 1 whitespace character - * @see Character#isWhitespace - */ - public static boolean containsWhitespace(CharSequence str) { - if (!hasLength(str)) { - return false; - } - - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given {@code String} contains any whitespace characters. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not empty and - * contains at least 1 whitespace character - * @see #containsWhitespace(CharSequence) - */ - public static boolean containsWhitespace(String str) { - return containsWhitespace((CharSequence) str); - } - - /** - * Trim leading and trailing whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { - sb.deleteCharAt(0); - } - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Trim all whitespace from the given {@code String}: - * leading, trailing, and in between characters. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimAllWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - int len = str.length(); - StringBuilder sb = new StringBuilder(str.length()); - for (int i = 0; i < len; i++) { - char c = str.charAt(i); - if (!Character.isWhitespace(c)) { - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Trim leading whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimLeadingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { - sb.deleteCharAt(0); - } - return sb.toString(); - } - - /** - * Trim trailing whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimTrailingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Trim all occurrences of the supplied leading character from the given {@code String}. - * @param str the {@code String} to check - * @param leadingCharacter the leading character to be trimmed - * @return the trimmed {@code String} - */ - public static String trimLeadingCharacter(String str, char leadingCharacter) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) { - sb.deleteCharAt(0); - } - return sb.toString(); - } - - /** - * Trim all occurrences of the supplied trailing character from the given {@code String}. - * @param str the {@code String} to check - * @param trailingCharacter the trailing character to be trimmed - * @return the trimmed {@code String} - */ - public static String trimTrailingCharacter(String str, char trailingCharacter) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Test if the given {@code String} starts with the specified prefix, - * ignoring upper/lower case. - * @param str the {@code String} to check - * @param prefix the prefix to look for - * @see String#startsWith - */ - public static boolean startsWithIgnoreCase(String str, String prefix) { - return (str != null && prefix != null && str.length() >= prefix.length() && - str.regionMatches(true, 0, prefix, 0, prefix.length())); - } - - /** - * Test if the given {@code String} ends with the specified suffix, - * ignoring upper/lower case. - * @param str the {@code String} to check - * @param suffix the suffix to look for - * @see String#endsWith - */ - public static boolean endsWithIgnoreCase(String str, String suffix) { - return (str != null && suffix != null && str.length() >= suffix.length() && - str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length())); - } - - /** - * Test whether the given string matches the given substring - * at the given index. - * @param str the original string (or StringBuilder) - * @param index the index in the original string to start matching against - * @param substring the substring to match at the given index - */ - public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { - if (index + substring.length() > str.length()) { - return false; - } - for (int i = 0; i < substring.length(); i++) { - if (str.charAt(index + i) != substring.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Count the occurrences of the substring {@code sub} in string {@code str}. - * @param str string to search in - * @param sub string to search for - */ - public static int countOccurrencesOf(String str, String sub) { - if (!hasLength(str) || !hasLength(sub)) { - return 0; - } - - int count = 0; - int pos = 0; - int idx; - while ((idx = str.indexOf(sub, pos)) != -1) { - ++count; - pos = idx + sub.length(); - } - return count; - } - - /** - * Replace all occurrences of a substring within a string with another string. - * @param inString {@code String} to examine - * @param oldPattern {@code String} to replace - * @param newPattern {@code String} to insert - * @return a {@code String} with the replacements - */ - public static String replace(String inString, String oldPattern, String newPattern) { - if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { - return inString; - } - int index = inString.indexOf(oldPattern); - if (index == -1) { - // no occurrence -> can return input as-is - return inString; - } - - int capacity = inString.length(); - if (newPattern.length() > oldPattern.length()) { - capacity += 16; - } - StringBuilder sb = new StringBuilder(capacity); - - int pos = 0; // our position in the old string - int patLen = oldPattern.length(); - while (index >= 0) { - sb.append(inString.substring(pos, index)); - sb.append(newPattern); - pos = index + patLen; - index = inString.indexOf(oldPattern, pos); - } - - // append any characters to the right of a match - sb.append(inString.substring(pos)); - return sb.toString(); - } - - /** - * Delete all occurrences of the given substring. - * @param inString the original {@code String} - * @param pattern the pattern to delete all occurrences of - * @return the resulting {@code String} - */ - public static String delete(String inString, String pattern) { - return replace(inString, pattern, ""); - } - - /** - * Delete any character in a given {@code String}. - * @param inString the original {@code String} - * @param charsToDelete a set of characters to delete. - * E.g. "az\n" will delete 'a's, 'z's and new lines. - * @return the resulting {@code String} - */ - public static String deleteAny(String inString, String charsToDelete) { - if (!hasLength(inString) || !hasLength(charsToDelete)) { - return inString; - } - - StringBuilder sb = new StringBuilder(inString.length()); - for (int i = 0; i < inString.length(); i++) { - char c = inString.charAt(i); - if (charsToDelete.indexOf(c) == -1) { - sb.append(c); - } - } - return sb.toString(); - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with formatted Strings - //--------------------------------------------------------------------- - - /** - * Quote the given {@code String} with single quotes. - * @param str the input {@code String} (e.g. "myString") - * @return the quoted {@code String} (e.g. "'myString'"), - * or {@code null} if the input was {@code null} - */ - public static String quote(String str) { - return (str != null ? "'" + str + "'" : null); - } - - /** - * Turn the given Object into a {@code String} with single quotes - * if it is a {@code String}; keeping the Object as-is else. - * @param obj the input Object (e.g. "myString") - * @return the quoted {@code String} (e.g. "'myString'"), - * or the input object as-is if not a {@code String} - */ - public static Object quoteIfString(Object obj) { - return (obj instanceof String ? quote((String) obj) : obj); - } - - /** - * Unqualify a string qualified by a '.' dot character. For example, - * "this.name.is.qualified", returns "qualified". - * @param qualifiedName the qualified name - */ - public static String unqualify(String qualifiedName) { - return unqualify(qualifiedName, '.'); - } - - /** - * Unqualify a string qualified by a separator character. For example, - * "this:name:is:qualified" returns "qualified" if using a ':' separator. - * @param qualifiedName the qualified name - * @param separator the separator - */ - public static String unqualify(String qualifiedName, char separator) { - return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); - } - - /** - * Capitalize a {@code String}, changing the first letter to - * upper case as per {@link Character#toUpperCase(char)}. - * No other letters are changed. - * @param str the {@code String} to capitalize - * @return the capitalized {@code String} - */ - public static String capitalize(String str) { - return changeFirstCharacterCase(str, true); - } - - /** - * Uncapitalize a {@code String}, changing the first letter to - * lower case as per {@link Character#toLowerCase(char)}. - * No other letters are changed. - * @param str the {@code String} to uncapitalize - * @return the uncapitalized {@code String} - */ - public static String uncapitalize(String str) { - return changeFirstCharacterCase(str, false); - } - - private static String changeFirstCharacterCase(String str, boolean capitalize) { - if (!hasLength(str)) { - return str; - } - - char baseChar = str.charAt(0); - char updatedChar; - if (capitalize) { - updatedChar = Character.toUpperCase(baseChar); - } - else { - updatedChar = Character.toLowerCase(baseChar); - } - if (baseChar == updatedChar) { - return str; - } - - char[] chars = str.toCharArray(); - chars[0] = updatedChar; - return new String(chars, 0, chars.length); - } - - /** - * Extract the filename from the given Java resource path, - * e.g. {@code "mypath/myfile.txt" -> "myfile.txt"}. - * @param path the file path (may be {@code null}) - * @return the extracted filename, or {@code null} if none - */ - public static String getFilename(String path) { - if (path == null) { - return null; - } - - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); - } - - /** - * Extract the filename extension from the given Java resource path, - * - * @param path the file path (may be {@code null}) - * @return the extracted filename extension, or {@code null} if none - */ - public static String getFilenameExtension(String path) { - if (path == null) { - return null; - } - - int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - if (extIndex == -1) { - return null; - } - - int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (folderIndex > extIndex) { - return null; - } - - return path.substring(extIndex + 1); - } - - /** - * Strip the filename extension from the given Java resource path, - * - * @param path the file path - * @return the path with stripped filename extension - */ - public static String stripFilenameExtension(String path) { - if (path == null) { - return null; - } - - int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - if (extIndex == -1) { - return path; - } - - int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (folderIndex > extIndex) { - return path; - } - - return path.substring(0, extIndex); - } - - /** - * Apply the given relative path to the given Java resource path, - * assuming standard Java folder separation (i.e. "/" separators). - * @param path the path to start from (usually a full file path) - * @param relativePath the relative path to apply - * (relative to the full file path above) - * @return the full file path that results from applying the relative path - */ - public static String applyRelativePath(String path, String relativePath) { - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (separatorIndex != -1) { - String newPath = path.substring(0, separatorIndex); - if (!relativePath.startsWith(FOLDER_SEPARATOR)) { - newPath += FOLDER_SEPARATOR; - } - return newPath + relativePath; - } - else { - return relativePath; - } - } - - /** - * Normalize the path by suppressing sequences like "path/.." and - * inner simple dots. - *

The result is convenient for path comparison. For other uses, - * notice that Windows separators ("\") are replaced by simple slashes. - * @param path the original path - * @return the normalized path - */ - public static String cleanPath(String path) { - if (path == null) { - return null; - } - String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); - - // Strip prefix from path to analyze, to not treat it as part of the - // first path element. This is necessary to correctly parse paths like - // "file:core/../core/io/Resource.class", where the ".." should just - // strip the first "core" directory while keeping the "file:" prefix. - int prefixIndex = pathToUse.indexOf(":"); - String prefix = ""; - if (prefixIndex != -1) { - prefix = pathToUse.substring(0, prefixIndex + 1); - if (prefix.contains("/")) { - prefix = ""; - } - else { - pathToUse = pathToUse.substring(prefixIndex + 1); - } - } - if (pathToUse.startsWith(FOLDER_SEPARATOR)) { - prefix = prefix + FOLDER_SEPARATOR; - pathToUse = pathToUse.substring(1); - } - - String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); - List pathElements = new LinkedList(); - int tops = 0; - - for (int i = pathArray.length - 1; i >= 0; i--) { - String element = pathArray[i]; - if (CURRENT_PATH.equals(element)) { - // Points to current directory - drop it. - } - else if (TOP_PATH.equals(element)) { - // Registering top path found. - tops++; - } - else { - if (tops > 0) { - // Merging path element with element corresponding to top path. - tops--; - } - else { - // Normal path element found. - pathElements.add(0, element); - } - } - } - - // Remaining top paths need to be retained. - for (int i = 0; i < tops; i++) { - pathElements.add(0, TOP_PATH); - } - - return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); - } - - /** - * Compare two paths after normalization of them. - * @param path1 first path for comparison - * @param path2 second path for comparison - * @return whether the two paths are equivalent after normalization - */ - public static boolean pathEquals(String path1, String path2) { - return cleanPath(path1).equals(cleanPath(path2)); - } - - /** - * Parse the given {@code localeString} value into a {@link Locale}. - *

This is the inverse operation of {@link Locale#toString Locale's toString}. - * @param localeString the locale {@code String}, following {@code Locale's} - * {@code toString()} format ("en", "en_UK", etc); - * also accepts spaces as separators, as an alternative to underscores - * @return a corresponding {@code Locale} instance, or {@code null} if none - * @throws IllegalArgumentException in case of an invalid locale specification - */ - public static Locale parseLocaleString(String localeString) { - String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); - String language = (parts.length > 0 ? parts[0] : ""); - String country = (parts.length > 1 ? parts[1] : ""); - - validateLocalePart(language); - validateLocalePart(country); - - String variant = ""; - if (parts.length > 2) { - // There is definitely a variant, and it is everything after the country - // code sans the separator between the country code and the variant. - int endIndexOfCountryCode = localeString.indexOf(country, language.length()) + country.length(); - // Strip off any leading '_' and whitespace, what's left is the variant. - variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); - if (variant.startsWith("_")) { - variant = trimLeadingCharacter(variant, '_'); - } - } - return (language.length() > 0 ? new Locale(language, country, variant) : null); - } - - private static void validateLocalePart(String localePart) { - for (int i = 0; i < localePart.length(); i++) { - char ch = localePart.charAt(i); - if (ch != ' ' && ch != '_' && ch != '#' && !Character.isLetterOrDigit(ch)) { - throw new IllegalArgumentException( - "Locale part \"" + localePart + "\" contains invalid characters"); - } - } - } - - /** - * Determine the RFC 3066 compliant language tag, - * as used for the HTTP "Accept-Language" header. - * @param locale the Locale to transform to a language tag - * @return the RFC 3066 compliant language tag as {@code String} - */ - public static String toLanguageTag(Locale locale) { - return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); - } - - /** - * Parse the given {@code timeZoneString} value into a {@link TimeZone}. - * @param timeZoneString the time zone {@code String}, following {@link TimeZone#getTimeZone(String)} - * but throwing {@link IllegalArgumentException} in case of an invalid time zone specification - * @return a corresponding {@link TimeZone} instance - * @throws IllegalArgumentException in case of an invalid time zone specification - */ - public static TimeZone parseTimeZoneString(String timeZoneString) { - TimeZone timeZone = TimeZone.getTimeZone(timeZoneString); - if ("GMT".equals(timeZone.getID()) && !timeZoneString.startsWith("GMT")) { - // We don't want that GMT fallback... - throw new IllegalArgumentException("Invalid time zone specification '" + timeZoneString + "'"); - } - return timeZone; - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with String arrays - //--------------------------------------------------------------------- - - /** - * Append the given {@code String} to the given {@code String} array, - * returning a new array consisting of the input array contents plus - * the given {@code String}. - * @param array the array to append to (can be {@code null}) - * @param str the {@code String} to append - * @return the new array (never {@code null}) - */ - public static String[] addStringToArray(String[] array, String str) { - if (ObjectUtils.isEmpty(array)) { - return new String[] {str}; - } - - String[] newArr = new String[array.length + 1]; - System.arraycopy(array, 0, newArr, 0, array.length); - newArr[array.length] = str; - return newArr; - } - - /** - * Concatenate the given {@code String} arrays into one, - * with overlapping array elements included twice. - *

The order of elements in the original arrays is preserved. - * @param array1 the first array (can be {@code null}) - * @param array2 the second array (can be {@code null}) - * @return the new array ({@code null} if both given arrays were {@code null}) - */ - public static String[] concatenateStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - - String[] newArr = new String[array1.length + array2.length]; - System.arraycopy(array1, 0, newArr, 0, array1.length); - System.arraycopy(array2, 0, newArr, array1.length, array2.length); - return newArr; - } - - /** - * Merge the given {@code String} arrays into one, with overlapping - * array elements only included once. - *

The order of elements in the original arrays is preserved - * (with the exception of overlapping elements, which are only - * included on their first occurrence). - * @param array1 the first array (can be {@code null}) - * @param array2 the second array (can be {@code null}) - * @return the new array ({@code null} if both given arrays were {@code null}) - */ - public static String[] mergeStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - - List result = new ArrayList(); - result.addAll(Arrays.asList(array1)); - for (String str : array2) { - if (!result.contains(str)) { - result.add(str); - } - } - return toStringArray(result); - } - - /** - * Turn given source {@code String} array into sorted array. - * @param array the source array - * @return the sorted array (never {@code null}) - */ - public static String[] sortStringArray(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - - Arrays.sort(array); - return array; - } - - /** - * Copy the given {@code Collection} into a {@code String} array. - *

The {@code Collection} must contain {@code String} elements only. - * @param collection the {@code Collection} to copy - * @return the {@code String} array - */ - public static String[] toStringArray(Collection collection) { - if (collection == null) { - return null; - } - - return collection.toArray(new String[collection.size()]); - } - - /** - * Copy the given Enumeration into a {@code String} array. - * The Enumeration must contain {@code String} elements only. - * @param enumeration the Enumeration to copy - * @return the {@code String} array - */ - public static String[] toStringArray(Enumeration enumeration) { - if (enumeration == null) { - return null; - } - - List list = Collections.list(enumeration); - return list.toArray(new String[list.size()]); - } - - /** - * Trim the elements of the given {@code String} array, - * calling {@code String.trim()} on each of them. - * @param array the original {@code String} array - * @return the resulting array (of the same size) with trimmed elements - */ - public static String[] trimArrayElements(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - - String[] result = new String[array.length]; - for (int i = 0; i < array.length; i++) { - String element = array[i]; - result[i] = (element != null ? element.trim() : null); - } - return result; - } - - /** - * Remove duplicate strings from the given array. - *

As of 4.2, it preserves the original order, as it uses a {@link LinkedHashSet}. - * @param array the {@code String} array - * @return an array without duplicates, in natural sort order - */ - public static String[] removeDuplicateStrings(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return array; - } - - Set set = new LinkedHashSet(); - for (String element : array) { - set.add(element); - } - return toStringArray(set); - } - - /** - * Split a {@code String} at the first occurrence of the delimiter. - * Does not include the delimiter in the result. - * @param toSplit the string to split - * @param delimiter to split the string up with - * @return a two element array with index 0 being before the delimiter, and - * index 1 being after the delimiter (neither element includes the delimiter); - * or {@code null} if the delimiter wasn't found in the given input {@code String} - */ - public static String[] split(String toSplit, String delimiter) { - if (!hasLength(toSplit) || !hasLength(delimiter)) { - return null; - } - int offset = toSplit.indexOf(delimiter); - if (offset < 0) { - return null; - } - - String beforeDelimiter = toSplit.substring(0, offset); - String afterDelimiter = toSplit.substring(offset + delimiter.length()); - return new String[] {beforeDelimiter, afterDelimiter}; - } - - /** - * Take an array of strings and split each element based on the given delimiter. - * A {@code Properties} instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * {@code Properties} instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @return a {@code Properties} instance representing the array contents, - * or {@code null} if the array to process was {@code null} or empty - */ - public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { - return splitArrayElementsIntoProperties(array, delimiter, null); - } - - /** - * Take an array of strings and split each element based on the given delimiter. - * A {@code Properties} instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * {@code Properties} instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @param charsToDelete one or more characters to remove from each element - * prior to attempting the split operation (typically the quotation mark - * symbol), or {@code null} if no removal should occur - * @return a {@code Properties} instance representing the array contents, - * or {@code null} if the array to process was {@code null} or empty - */ - public static Properties splitArrayElementsIntoProperties( - String[] array, String delimiter, String charsToDelete) { - - if (ObjectUtils.isEmpty(array)) { - return null; - } - - Properties result = new Properties(); - for (String element : array) { - if (charsToDelete != null) { - element = deleteAny(element, charsToDelete); - } - String[] splittedElement = split(element, delimiter); - if (splittedElement == null) { - continue; - } - result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); - } - return result; - } - - /** - * Tokenize the given {@code String} into a {@code String} array via a - * {@link StringTokenizer}. - *

Trims tokens and omits empty tokens. - *

The given {@code delimiters} string can consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using {@link #delimitedListToStringArray}. - * @param str the {@code String} to tokenize - * @param delimiters the delimiter characters, assembled as a {@code String} - * (each of the characters is individually considered as a delimiter) - * @return an array of the tokens - * @see StringTokenizer - * @see String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray(String str, String delimiters) { - return tokenizeToStringArray(str, delimiters, true, true); - } - - /** - * Tokenize the given {@code String} into a {@code String} array via a - * {@link StringTokenizer}. - *

The given {@code delimiters} string can consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using {@link #delimitedListToStringArray}. - * @param str the {@code String} to tokenize - * @param delimiters the delimiter characters, assembled as a {@code String} - * (each of the characters is individually considered as a delimiter) - * @param trimTokens trim the tokens via {@link String#trim()} - * @param ignoreEmptyTokens omit empty tokens from the result array - * (only applies to tokens that are empty after trimming; StringTokenizer - * will not consider subsequent delimiters as token in the first place). - * @return an array of the tokens - * @see StringTokenizer - * @see String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray( - String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { - - if (str == null) { - return null; - } - - StringTokenizer st = new StringTokenizer(str, delimiters); - List tokens = new ArrayList(); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (trimTokens) { - token = token.trim(); - } - if (!ignoreEmptyTokens || token.length() > 0) { - tokens.add(token); - } - } - return toStringArray(tokens); - } - - /** - * Take a {@code String} that is a delimited list and convert it into a - * {@code String} array. - *

A single {@code delimiter} may consist of more than one character, - * but it will still be considered as a single delimiter string, rather - * than as bunch of potential delimiter characters, in contrast to - * {@link #tokenizeToStringArray}. - * @param str the input {@code String} - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter) { - return delimitedListToStringArray(str, delimiter, null); - } - - /** - * Take a {@code String} that is a delimited list and convert it into - * a {@code String} array. - *

A single {@code delimiter} may consist of more than one character, - * but it will still be considered as a single delimiter string, rather - * than as bunch of potential delimiter characters, in contrast to - * {@link #tokenizeToStringArray}. - * @param str the input {@code String} - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @param charsToDelete a set of characters to delete; useful for deleting unwanted - * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a {@code String} - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { - if (str == null) { - return new String[0]; - } - if (delimiter == null) { - return new String[] {str}; - } - - List result = new ArrayList(); - if ("".equals(delimiter)) { - for (int i = 0; i < str.length(); i++) { - result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); - } - } - else { - int pos = 0; - int delPos; - while ((delPos = str.indexOf(delimiter, pos)) != -1) { - result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); - pos = delPos + delimiter.length(); - } - if (str.length() > 0 && pos <= str.length()) { - // Add rest of String, but not in case of empty input. - result.add(deleteAny(str.substring(pos), charsToDelete)); - } - } - return toStringArray(result); - } - - /** - * Convert a comma delimited list (e.g., a row from a CSV file) into an - * array of strings. - * @param str the input {@code String} - * @return an array of strings, or the empty array in case of empty input - */ - public static String[] commaDelimitedListToStringArray(String str) { - return delimitedListToStringArray(str, ","); - } - - /** - * Convert a comma delimited list (e.g., a row from a CSV file) into a set. - *

Note that this will suppress duplicates, and as of 4.2, the elements in - * the returned set will preserve the original order in a {@link LinkedHashSet}. - * @param str the input {@code String} - * @return a set of {@code String} entries in the list - * @see #removeDuplicateStrings(String[]) - */ - public static Set commaDelimitedListToSet(String str) { - Set set = new LinkedHashSet(); - String[] tokens = commaDelimitedListToStringArray(str); - for (String token : tokens) { - set.add(token); - } - return set; - } - - /** - * Convert a {@link Collection} to a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @param delim the delimiter to use (typically a ",") - * @param prefix the {@code String} to start each element with - * @param suffix the {@code String} to end each element with - * @return the delimited {@code String} - */ - public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { - if (CollectionUtils.isEmpty(coll)) { - return ""; - } - - StringBuilder sb = new StringBuilder(); - Iterator it = coll.iterator(); - while (it.hasNext()) { - sb.append(prefix).append(it.next()).append(suffix); - if (it.hasNext()) { - sb.append(delim); - } - } - return sb.toString(); - } - - /** - * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @param delim the delimiter to use (typically a ",") - * @return the delimited {@code String} - */ - public static String collectionToDelimitedString(Collection coll, String delim) { - return collectionToDelimitedString(coll, delim, "", ""); - } - - /** - * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @return the delimited {@code String} - */ - public static String collectionToCommaDelimitedString(Collection coll) { - return collectionToDelimitedString(coll, ","); - } - - /** - * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param arr the array to display - * @param delim the delimiter to use (typically a ",") - * @return the delimited {@code String} - */ - public static String arrayToDelimitedString(Object[] arr, String delim) { - if (ObjectUtils.isEmpty(arr)) { - return ""; - } - if (arr.length == 1) { - return ObjectUtils.nullSafeToString(arr[0]); - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < arr.length; i++) { - if (i > 0) { - sb.append(delim); - } - sb.append(arr[i]); - } - return sb.toString(); - } - - /** - * Convert a {@code String} array into a comma delimited {@code String} - * (i.e., CSV). - *

Useful for {@code toString()} implementations. - * @param arr the array to display - * @return the delimited {@code String} - */ - public static String arrayToCommaDelimitedString(Object[] arr) { - return arrayToDelimitedString(arr, ","); - } - - /** - *

Compares two CharSequences, returning {@code true} if they represent - * equal sequences of characters.

- * - *

{@code null}s are handled without exceptions. Two {@code null} - * references are considered to be equal. The comparison is case sensitive.

- * - *
-     * StringUtils.equals(null, null)   = true
-     * StringUtils.equals(null, "abc")  = false
-     * StringUtils.equals("abc", null)  = false
-     * StringUtils.equals("abc", "abc") = true
-     * StringUtils.equals("abc", "ABC") = false
-     * 
- * - * @see Object#equals(Object) - * @param cs1 the first CharSequence, may be {@code null} - * @param cs2 the second CharSequence, may be {@code null} - * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} - * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) - */ - public static boolean equals(final CharSequence cs1, final CharSequence cs2) { - if (cs1 == cs2) { - return true; - } - if (cs1 == null || cs2 == null) { - return false; - } - if (cs1.length() != cs2.length()) { - return false; - } - if (cs1 instanceof String && cs2 instanceof String) { - return cs1.equals(cs2); - } - return regionMatches(cs1, false, 0, cs2, 0, cs1.length()); - } - - /** - * Green implementation of regionMatches. - * - * @param cs the {@code CharSequence} to be processed - * @param ignoreCase whether or not to be case insensitive - * @param thisStart the index to start on the {@code cs} CharSequence - * @param substring the {@code CharSequence} to be looked for - * @param start the index to start on the {@code substring} CharSequence - * @param length character length of the region - * @return whether the region matched - */ - static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, - final CharSequence substring, final int start, final int length) { - if (cs instanceof String && substring instanceof String) { - return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); - } - int index1 = thisStart; - int index2 = start; - int tmpLen = length; - - // Extract these first so we detect NPEs the same as the java.lang.String version - final int srcLen = cs.length() - thisStart; - final int otherLen = substring.length() - start; - - // Check for invalid parameters - if (thisStart < 0 || start < 0 || length < 0) { - return false; - } - - // Check that the regions are long enough - if (srcLen < length || otherLen < length) { - return false; - } - - while (tmpLen-- > 0) { - final char c1 = cs.charAt(index1++); - final char c2 = substring.charAt(index2++); - - if (c1 == c2) { - continue; - } - - if (!ignoreCase) { - return false; - } - - // The same check as in String.regionMatches(): - if (Character.toUpperCase(c1) != Character.toUpperCase(c2) - && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { - return false; - } - } - - return true; - } - }