Domanda

Lo so, ora ho due problemi. Ma mi sto divertendo!

Ho iniziato con questo consiglio non di cercare di dividere, ma invece di abbinare ciò che è un campo accettabile, e da lì si è esteso a questa espressione.

final Pattern pattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?=,|$)");

L'espressione è simile a questa senza le fastidiose citazioni di escape:

"([^"]*)"|(?<=,|^)([^,]*)(?=,|$)

Questo sta funzionando bene per me - o corrisponde su "due virgolette e qualunque cosa sia tra loro", o "qualcosa tra l'inizio della riga o una virgola e la fine della riga o una virgola". Scorrere le partite mi dà tutti i campi, anche se sono vuoti. Ad esempio,

the quick, "brown, fox jumps", over, "the",,"lazy dog"

si suddivide in

the quick
"brown, fox jumps"
over
"the"

"lazy dog"

Grande! Ora voglio eliminare le virgolette, quindi ho aggiunto il lookahead e il lookbehind ai gruppi non catturanti come stavo facendo per le virgole.

final Pattern pattern = Pattern.compile("(?<=\")([^\"]*)(?=\")|(?<=,|^)([^,]*)(?=,|$)");

di nuovo l'espressione è:

(?<=")([^"]*)(?=")|(?<=,|^)([^,]*)(?=,|$)

Invece del risultato desiderato

the quick
brown, fox jumps
over
the

lazy dog

ora ho questa suddivisione:

the quick
"brown
 fox jumps"
,over,
"the"
,,
"lazy dog"

Cosa mi sto perdendo?

È stato utile?

Soluzione

Precedenza dell'operatore. Fondamentalmente non ce n'è. È tutto da sinistra a destra. Quindi o (|) si applica al lookahead della citazione di chiusura e al lookahead della virgola

Prova:

(?:(?<=")([^"]*)(?="))|(?<=,|^)([^,]*)(?=,|$)

Altri suggerimenti

(?:^|,)\s*(?:(?:(?=")"([^"].*?)")|(?:(?!")(.*?)))(?=,|$)

Questo dovrebbe fare quello che vuoi.

Spiegazione:

(?:^|,)\s*

Il modello dovrebbe iniziare con una, o inizio della stringa. Inoltre, ignora tutti gli spazi all'inizio.

Lookahead e vedi se il resto inizia con un preventivo

(?:(?=")"([^"].*?)")

In tal caso, abbina senza avidità fino alla prossima citazione.

(?:(?!")(.*?))

Se non inizia con una citazione, quindi abbina senza avidità fino alla virgola successiva o alla fine della stringa.

(?=,|$)

Il modello dovrebbe terminare con una virgola o fine della stringa.

Quando ho iniziato a capire cosa avevo fatto di sbagliato, ho anche iniziato a capire quanto fossero contorti i lookaround. Alla fine ho capito che non volevo tutto il testo corrispondente, volevo gruppi specifici all'interno di esso. Ho finito per usare qualcosa di molto simile al mio RegEx originale, tranne per il fatto che non ho fatto uno sguardo alla virgola di chiusura, che penso dovrebbe essere un po 'più efficiente. Ecco il mio codice finale.

package regex.parser;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CSVParser {

    /*
     * This Pattern will match on either quoted text or text between commas, including
     * whitespace, and accounting for beginning and end of line.
     */
    private final Pattern csvPattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?:,|$)");  
    private ArrayList<String> allMatches = null;    
    private Matcher matcher = null;
    private String match = null;
    private int size;

    public CSVParser() {        
        allMatches = new ArrayList<String>();
        matcher = null;
        match = null;
    }

    public String[] parse(String csvLine) {
        matcher = csvPattern.matcher(csvLine);
        allMatches.clear();
        String match;
        while (matcher.find()) {
            match = matcher.group(1);
            if (match!=null) {
                allMatches.add(match);
            }
            else {
                allMatches.add(matcher.group(2));
            }
        }

        size = allMatches.size();       
        if (size > 0) {
            return allMatches.toArray(new String[size]);
        }
        else {
            return new String[0];
        }           
    }   

    public static void main(String[] args) {        
        String lineinput = "the quick,\"brown, fox jumps\",over,\"the\",,\"lazy dog\"";

        CSVParser myCSV = new CSVParser();
        System.out.println("Testing CSVParser with: \n " + lineinput);
        for (String s : myCSV.parse(lineinput)) {
            System.out.println(s);
        }
    }

}

So che questo non è ciò che l'OP vuole, ma per gli altri lettori, uno dei metodi String.replace potrebbe essere usato per eliminare le virgolette da ciascun elemento nella matrice dei risultati della regex corrente degli OP.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top