Analizzare CSV con doppia quotazione in alcuni casi

Ho csv che viene fornito con formato:

a1, a2, a3, a4,a5″, a6

Solo campo , avrà preventivi

Utilizzo di Java, come facilmente analizzare questo? Cerco di evitare l’uso di open source CSV parser come politica aziendale. Grazie.

  • Idea facilmente, CSV ha un paio di fastidiosi casi limite: escape virgolette, utilizzando diversi stili non meno; e a capo, in valori di campo – divertente se avete da segnalare gli errori con il CSV di linea che si è verificato sul. Se non è possibile usare un parser e potrebbe avere a che fare con questi, scrivere un parser. (Che è anche divertente da fare, se non ti è permesso un generatore di parser.)
  • se l’azienda chiede non open source libs {a prescindere dalla licenza) e avete bisogno di aiuto con un semplice analizzare…
  • l’analisi è di circa 30lines di mano il codice scritto, non c’è bisogno per il generatore.
  • possibile duplicato di l’Analisi di CSV in java
InformationsquelleAutor HP. | 2011-10-17



4 Replies
  1. 24

    Si potrebbe utilizzare Matcher.find con la seguente espressione regolare:

    \s*("[^"]*"|[^,]*)\s* 
    

    Ecco un esempio più completo:

    String s = "a1, a2, a3, \"a4,a5\", a6";
    Pattern pattern = Pattern.compile("\\s*(\"[^\"]*\"|[^,]*)\\s*");
    Matcher matcher = pattern.matcher(s);
    while (matcher.find()) {
        System.out.println(matcher.group(1));
    }

    Vederlo lavorare online: ideone

    • Più in generale, in un file CSV, per un valore è racchiuso tra virgolette, come presto in quanto contiene un separatore, una nuova riga e/o preventivi di…
    • le virgolette doppie (“”) viene utilizzato per rappresentare un singolo “. Inoltre, usare le regExp è al di là di overkill
    • Questo non funziona bene perché aggiunge una stringa vuota tra elementi e questo crea un problema se non ci sono celle vuote nel file csv.
    • Questa è una risposta migliore (non aggiungere stringhe vuote): stackoverflow.com/a/15739087/1068385
  2. 3

    Mi sono imbattuto in questo stesso problema (ma in Python), in un modo che ho trovato per risolvere il problema, senza espressioni regolari, è stata:
    Quando si ottiene la linea, controllare per eventuali preventivi, se ci sono citazioni, dividere una stringa tra virgolette, e dividere il anche risultati indicizzati dell’array risultante sulle virgole. Il dispari indicizzati corde dovrebbe essere pieno citato valori.

    Io non sono un programmatore Java, in modo da prendere questo come pseudocodice…

    line = String[];
        if ('"' in row){
            vals = row.split('"');
            for (int i =0; i<vals.length();i+=2){
                line+=vals[i].split(',');
            }
            for (int j=1; j<vals.length();j+=2){
                line+=vals[j];
            }
        }
        else{
            line = row.split(',')
        }

    In alternativa, utilizzare le espressioni regolari.

  3. 3

    Qui è un po ‘ di codice per voi, spero che utilizza codice al di fuori di qui non conta open source, che è.

    package bestsss.util;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class SplitCSVLine {
        public static String[] splitCSV(BufferedReader reader) throws IOException{
            return splitCSV(reader, null, ',', '"');
        }
    
        /**
         * 
         * @param reader - some line enabled reader, we lazy
         * @param expectedColumns - convenient int[1] to return the expected
         * @param separator - the C(omma) SV (or alternative like semi-colon) 
         * @param quote - double quote char ('"') or alternative
         * @return String[] containing the field
         * @throws IOException
         */
        public static String[] splitCSV(BufferedReader reader, int[] expectedColumns, char separator, char quote) throws IOException{       
            final List<String> tokens = new ArrayList<String>(expectedColumns==null?8:expectedColumns[0]);
            final StringBuilder sb = new StringBuilder(24);
    
            for(boolean quoted=false;;sb.append('\n')) {//lazy, we do not preserve the original new line, but meh
                final String line = reader.readLine();
                if (line==null)
                    break;
                for (int i = 0, len= line.length(); i < len; i++) { 
                    final char c = line.charAt(i);
                    if (c == quote) {
                        if( quoted   && i<len-1 && line.charAt(i+1) == quote ){//2xdouble quote in quoted 
                            sb.append(c);
                            i++;//skip it
                        }else{
                            if (quoted){
                                //next symbol must be either separator or eol according to RFC 4180
                                if (i==len-1 || line.charAt(i+1) == separator){
                                    quoted = false;
                                    continue;
                                }
                            } else{//not quoted
                                if (sb.length()==0){//at the very start
                                    quoted=true;
                                    continue;
                                }
                            }
                            //if fall here, bogus, just add the quote and move on; or throw exception if you like to
                            /*
                            5.  Each field may or may not be enclosed in double quotes (however
                               some programs, such as Microsoft Excel, do not use double quotes
                               at all).  If fields are not enclosed with double quotes, then
                               double quotes may not appear inside the fields.
                          */ 
                            sb.append(c);                   
                        }
                    } else if (c == separator && !quoted) {
                        tokens.add(sb.toString());
                        sb.setLength(0); 
                    } else {
                        sb.append(c);
                    }
                }
                if (!quoted)
                    break;      
            }
            tokens.add(sb.toString());//add last
            if (expectedColumns !=null)
                expectedColumns[0] = tokens.size();
            return tokens.toArray(new String[tokens.size()]);
        }
        public static void main(String[] args) throws Throwable{
            java.io.StringReader r = new java.io.StringReader("222,\"\"\"zzzz\", abc\"\" ,   111   ,\"1\n2\n3\n\"");
            System.out.println(java.util.Arrays.toString(splitCSV(new BufferedReader(r))));
        }
    }
  4. 1

    Sotto il codice sembra funzionare bene e in grado di gestire le citazioni all’interno di citazioni.

    final static Pattern quote = Pattern.compile("^\\s*\"((?:[^\"]|(?:\"\"))*?)\"\\s*,");
    
    public static List<String> parseCsv(String line) throws Exception
    {       
        List<String> list = new ArrayList<String>();
        line += ",";
    
        for (int x = 0; x < line.length(); x++)
        {
            String s = line.substring(x);
            if (s.trim().startsWith("\""))
            {
                Matcher m = quote.matcher(s);
                if (!m.find())
                    throw new Exception("CSV is malformed");
                list.add(m.group(1).replace("\"\"", "\""));
                x += m.end() - 1;
            }
            else
            {
                int y = s.indexOf(",");
                if (y == -1)
                    throw new Exception("CSV is malformed");
                list.add(s.substring(0, y));
                x += y;
            }
        }
        return list;
    }

Lascia un commento