Pregunta

Lo sé, ahora tengo dos problemas. ¡Pero me estoy divirtiendo!

Empecé con este consejo no intente dividir, sino que coincida en lo que es un campo aceptable, y se amplió desde allí a esta expresión.

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

La expresión se ve así sin las molestas comillas escapadas:

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

Esto funciona bien para mí, ya sea que coincida con "dos comillas y lo que sea que haya entre ellas", o "algo entre el comienzo de la línea o una coma y el final de la línea o una coma". Iterar a través de los partidos me da todos los campos, incluso si están vacíos. Por ejemplo,

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

se divide en

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

"lazy dog"

¡Genial! Ahora quiero descartar las comillas, así que agregué los grupos que no capturan con anticipación y con posterioridad como lo hacía para las comas.

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

nuevamente la expresión es:

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

En lugar del resultado deseado

the quick
brown, fox jumps
over
the

lazy dog

ahora obtengo este desglose:

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

¿Qué me estoy perdiendo?

¿Fue útil?

Solución

Precedencia del operador. Básicamente no hay ninguno. Todo es de izquierda a derecha. Entonces, o (|) se aplica a la comilla de cierre anticipada y la coma anticipada

Prueba:

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

Otros consejos

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

Esto debería hacer lo que quieras.

Explicación:

(?:^|,)\s*

El patrón debe comenzar con a, o al comienzo de la cadena. Además, ignore todos los espacios en blanco al principio.

Mire hacia adelante y vea si el resto comienza con una cita

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

Si es así, entonces coincida de manera no codiciosa hasta la próxima cita.

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

Si no comienza con una cita, entonces coincida de manera no codiciosa hasta la próxima coma o final de la cadena.

(?=,|$)

El patrón debe terminar con una coma o un final de cadena.

Cuando comencé a comprender lo que había hecho mal, también comencé a comprender cuán complicadas estaban las miradas. Finalmente me di cuenta de que no quería todo el texto coincidente, quería grupos específicos dentro de él. Terminé usando algo muy similar a mi RegEx original, excepto que no hice una búsqueda anticipada en la coma de cierre, que creo que debería ser un poco más eficiente. Aquí está mi código final.

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);
        }
    }

}

Sé que esto no es lo que quiere el OP, pero para otros lectores, uno de los métodos String.replace podría usarse para quitar las comillas de cada elemento en la matriz de resultados de la expresión regular actual de los OP.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top