Question

Je sais, maintenant j'ai deux problèmes. Mais je m'amuse!

J'ai commencé avec ce conseil "Ne pas essayer de scinder, mais plutôt de faire correspondre un champ acceptable, puis de l’étendre à cette expression.

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

L’expression ressemble à ceci sans les guillemets embêtés:

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

Cela fonctionne bien pour moi - cela correspond à "deux guillemets et ce qui les sépare", ou à "quelque chose entre le début de la ligne ou une virgule et la fin de la ligne ou une virgule". Itérer à travers les allumettes me procure tous les champs, même s'ils sont vides. Par exemple,

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

se décompose en

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

"lazy dog"

Génial! Maintenant, je veux supprimer les guillemets, alors j’ai ajouté le préfixe et regardé derrière les groupes non capturés, comme je le faisais pour les virgules.

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

encore l'expression est:

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

Au lieu du résultat souhaité

the quick
brown, fox jumps
over
the

lazy dog

maintenant je reçois cette ventilation:

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

Qu'est-ce qui me manque?

Était-ce utile?

La solution

Priorité de l'opérateur. Fondamentalement, il n'y en a pas. Tout est laissé à droite. Donc, ou (|) s'applique à la citation de fermeture et à la virgule

Essayez:

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

Autres conseils

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

Cela devrait faire ce que vous voulez.

Explication:

(?:^|,)\s*

Le motif doit commencer par un début de chaîne. Ignorez également tous les espaces au début.

Regardez avant et voyez si le reste commence par une citation

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

Si tel est le cas, associez-le de manière non goulue jusqu'au prochain passage.

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

S'il ne commence pas par un guillemet, faites une correspondance non avide avec la prochaine virgule ou la fin de la chaîne.

(?=,|$)

Le modèle doit se terminer par une virgule ou une fin de chaîne.

Quand j'ai commencé à comprendre ce que j'avais mal fait, j'ai aussi commencé à comprendre à quel point les lookarounds étaient compliqués. J'ai finalement réalisé que je ne voulais pas tout le texte correspondant, je voulais des groupes spécifiques à l'intérieur. J'ai fini par utiliser quelque chose de très similaire à mon RegEx original, à ceci près que je n'ai pas regardé la virgule de fermeture, ce qui, à mon avis, devrait être un peu plus efficace. Voici mon code 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);
        }
    }

}

Je sais que ce n'est pas ce que veut le PO, mais pour les autres lecteurs, l'une des méthodes String.replace pourrait être utilisée pour effacer les guillemets de chaque élément du tableau de résultats de la regex courante du PO.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top