Pergunta

Eu sei, agora eu tenho dois problemas. Mas estou me divertindo!

Eu comecei com este conselho não tentar dividir, mas sim para combinar sobre o que é um campo aceitável e expandiu a partir de lá para esta expressão.

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

Os olhares expressão como esta sem as aspas escaparam irritantes:

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

Isso está funcionando bem para mim - seja ele corresponde em "duas citações e tudo o que está entre eles", ou "algo entre o início da linha ou uma vírgula e o fim da linha ou uma vírgula". Iteração através dos jogos me recebe todos os campos, mesmo que estejam vazios. Por exemplo,

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

divide em

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

"lazy dog"

Great! Agora eu quero deixar cair as aspas, então eu adicionei o lookahead e lookbehind não capturar grupos como eu estava fazendo para as vírgulas.

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

novamente a expressão é:

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

Em vez do resultado desejado

the quick
brown, fox jumps
over
the

lazy dog

Agora eu recebo esta composição:

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

O que eu estou ausente?

Foi útil?

Solução

Operador de precedência. Basicamente não há nenhuma. É tudo esquerda para a direita. Assim, a ou (|) está aplicando à cotação de fechamento lookahead ea vírgula lookahead

Tente:

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

Outras dicas

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

Isso deve fazer o que quiser.

Explicação:

(?:^|,)\s*

O padrão deve começar com um, ou no início da string. Além disso, ignorar todos os espaços no início.

Lookahead e ver se o resto começa com uma citação

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

Se isso acontecer, então corresponder não avidamente até a próxima citação.

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

Se ele não começar com uma citação, em seguida, corresponder não avidamente até o próximo vírgula ou final de string.

(?=,|$)

O padrão deve terminar com uma vírgula ou fim de string.

Quando comecei a entender o que eu tinha feito de errado, eu também comecei a entender como complicado as lookarounds estavam fazendo isso. Eu finalmente percebi que eu não queria que todo o texto correspondente, eu queria grupos específicos dentro dele. Acabei usando algo muito semelhante ao meu RegEx original, exceto que eu não fiz um lookahead na vírgula fechamento, que eu acho que deve ser um pouco mais eficiente. Aqui está o meu 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);
        }
    }

}

Eu sei que isto não é o que o OP quer, mas para outros leitores, um dos métodos String.Replace poderia ser usado para tirar as aspas de cada elemento na matriz resultado da PO regex atual.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top