diff --git a/.rat-excludes b/.rat-excludes index 124cf995ed0..298ba4b109c 100644 --- a/.rat-excludes +++ b/.rat-excludes @@ -4,8 +4,6 @@ .rat-excludes # DISCLAIMER-WIP DISCLAIMER-WIP -# drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java -CsvLineParser.java # drools-decisiontables/src/test/resources/data/ComplexWorkbook.drl.csv ComplexWorkbook.drl.csv # drools-decisiontables/src/test/resources/data/TestCsv.drl.csv diff --git a/LICENSE b/LICENSE index fc4062804b2..5fe39d2c7a9 100644 --- a/LICENSE +++ b/LICENSE @@ -234,17 +234,6 @@ for drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/Ja (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------------ - for drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java - - Inner logic adapted from a C++ original that was Copyright (C) 1999 - Lucent Technologies Excerpted from 'The Practice of Programming' by Brian - Kernighan and Rob Pike. - - Included by permission of the http://tpop.awl.com/ web site, which says: - "You may use this code for any purpose, as long as you leave the - copyright notice and book citation attached." - ------------------------------------------------------------------------------------ for kie-dmn/kie-dmn-backend/src/test/resources/DC.xsd kie-dmn/kie-dmn-backend/src/test/resources/DI.xsd diff --git a/drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java b/drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java index 19aa1264514..4ee8e52a28c 100644 --- a/drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java +++ b/drools-decisiontables/src/main/java/org/drools/decisiontable/parser/csv/CsvLineParser.java @@ -1,150 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ package org.drools.decisiontable.parser.csv; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** - * - * a CSV line, with all the normal CSV features. + * A simple parser for CSV (Comma-Separated Values) format. + * Supports quoted fields and escaped quotes. */ public class CsvLineParser { - private ICsvParser lineParser; - - public CsvLineParser() { - this.lineParser = new CsvParserImpl(); - } + private static final char DELIMITER = ','; /** - * Use the current lineParser implementation to return a CSV line as a List - * of cells. (Strings). + * Parses a line of CSV text into a list of fields. + * + * @param input The CSV line to parse + * @return List of fields extracted from the CSV line */ - public List parse(final CharSequence line) { - return this.lineParser.parse( line.toString() ); - } - - /** - * This is insurance incase I need to replace it with more complex Csv - * handlers in the future. - */ - static interface ICsvParser { - public List parse(String line); - } - - /** - * Parse comma-separated values (CSV), a common Windows file format. Sample - * input: "LU",86.25,"11/4/1998","2:19PM",+4.0625 - *

- * Inner logic adapted from a C++ original that was Copyright (C) 1999 - * Lucent Technologies Excerpted from 'The Practice of Programming' by Brian - * W. Kernighan and Rob Pike. - *

- * Included by permission of the http://tpop.awl.com/ web site, which says: - * "You may use this code for any purpose, as long as you leave the - * copyright notice and book citation attached." I have done so. - * - * readability) - */ - static class CsvParserImpl - implements - ICsvParser { - - public static final char DEFAULT_SEP = ','; + public List parse(CharSequence input) { + String line = input != null ? input.toString() : ""; + List fields = new ArrayList<>(); - /** Construct a CSV parser, with the default separator (','). */ - public CsvParserImpl() { - this( CsvParserImpl.DEFAULT_SEP ); + if (line.isEmpty()) { + return Collections.singletonList(""); } - /** - * Construct a CSV parser with a given separator. - * - * @param sep - * The single char for the separator (not a list of separator - * characters) - */ - public CsvParserImpl(final char sep) { - this.fieldSep = sep; - } - - /** The fields in the current String */ - protected List list = new ArrayList<>(); + StringBuilder currentField = new StringBuilder(); + boolean insideQuotes = false; - /** the separator char for this parser */ - protected char fieldSep; + for (int i = 0; i < line.length(); i++) { + char currentChar = line.charAt(i); - /** - * parse: break the input String into fields - * - * @return java.util.Iterator containing each field from the original as - * a String, in order. - */ - public List parse(final String line) { - final StringBuilder sb = new StringBuilder(); - this.list.clear(); // recycle to initial state - int i = 0; - - if ( line.length() == 0 ) { - this.list.add( line ); - return this.list; - } - - do { - sb.setLength( 0 ); - if ( i < line.length() && line.charAt( i ) == '"' ) { - i = advQuoted( line, - sb, - ++i ); // skip + if (currentChar == '"') { + if (insideQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') { + // Handle escaped quotes + currentField.append('"'); + i++; // Skip the next quote } else { - i = advPlain( line, - sb, - i ); + insideQuotes = !insideQuotes; } - this.list.add( sb.toString() ); - i++; - } while ( i < line.length() ); - - return this.list; - } - - /** advQuoted: quoted field; return index of next separator */ - protected int advQuoted(final String s, - final StringBuilder sb, - final int i) { - int j; - final int len = s.length(); - for ( j = i; j < len; j++ ) { - if ( s.charAt( j ) == '"' && j + 1 < len ) { - if ( s.charAt( j + 1 ) == '"' ) { - j++; // skip escape char - } else if ( s.charAt( j + 1 ) == this.fieldSep ) { // next delimeter - j++; // skip end quotes - break; - } - } else if ( s.charAt( j ) == '"' && j + 1 == len ) { // end quotes at end of line - break; // done - } - sb.append( s.charAt( j ) ); // regular character. + continue; } - return j; - } - /** advPlain: unquoted field; return index of next separator */ - protected int advPlain(final String s, - final StringBuilder sb, - final int i) { - int j; - - j = s.indexOf( this.fieldSep, - i ); // look for separator - if ( j == -1 ) { // none found - sb.append( s.substring( i ) ); - return s.length(); - } else { - sb.append( s.substring( i, - j ) ); - return j; + if (currentChar == DELIMITER && !insideQuotes) { + fields.add(currentField.toString()); + currentField.setLength(0); + continue; } + + currentField.append(currentChar); } + // Add the last field + fields.add(currentField.toString()); + + return fields; } -} +} \ No newline at end of file