2009-10-21 9 views
3

Que serait une expression régulière pour trouver des ensembles de deux guillemets doubles non échappés qui sont contenus dans des colonnes mises entre guillemets dans un fichier CSV?Expression régulière pour trouver des guillemets doubles non échappés dans le fichier CSV

Pas un match:

"asdf","asdf" 
"", "asdf" 
"asdf", "" 
"adsf", "", "asdf" 

Match:

"asdf""asdf", "asdf" 
"asdf", """asdf""" 
"asdf", """" 
+0

Mes sauts de ligne étaient désactivés dans le message. Cela a-t-il du sens maintenant? –

+0

Oui c'est le cas. Voir ma suggestion –

Répondre

3

Essayez ceci:

(?m)""(?![ \t]*(,|$)) 

Explication:

(?m)  // enable multi-line matching (^ will act as the start of the line and $ will act as the end of the line (i)) 
""   // match two successive double quotes 
(?!  // start negative look ahead 
    [ \t]* // zero or more spaces or tabs 
    (  // open group 1 
    ,  //  match a comma 
    |  //  OR 
    $  //  the end of the line or string 
)  // close group 1 
)   // stop negative look ahead 

Ainsi, en anglais simple: « correspondance deux guillemets doubles successifs, que si elles n'ont pas une virgule ou en fin de -la ligne devant eux avec éventuellement des espaces et des tabulations entre ".

(i) en plus d'être les normales de début de la chaîne et fin de la chaîne caractères meta.

+0

Euh, cela ne correspondra pas à "asdf", "" '(ne devrait pas correspondre) mais pas à" asdf "" asdf "," asdf "' (devrait correspondre)? – Lucero

+0

@Lucero: non, exactement le contraire. Il ne correspond pas aux guillemets dans '" asdf "," "', et il DOIT correspondre aux guillemets doubles dans '" asdf "" asdf "," asdf "'. –

+0

Comment l'expression changerait si nous devions trouver des doubles guillemets non-successifs comme "asdf" quelque chose "asdf", "asdf", ... – stevenjmyu

0
".*"(\n|(".*",)*) 

devrait fonctionner, je suppose ...

+1

Notez que '. *' Est gourmand et peut manger n'importe quel nombre de caractères, y compris '' '', de sorte que par exemple '' adsf "," "," asdf "' serait aussi une correspondance. peut être assez mauvais car il correspond beaucoup à même dans le cas d'un non-match.) – Lucero

0

Pour les matches d'une seule ligne:

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

ou pour plusieurs lignes:

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

Modifier/Remarque: En fonction du moteur utilisé regex, vous pouvez utiliser d'autres trucs et assertions arrières pour faire la regex plus maigre. Mais cela devrait fonctionner dans la plupart des moteurs regex.

+0

Salut @Lucero, au cas où il vous serait utile de savoir, cela ne fonctionne pas sur le moteur regex NodeJS: > var x = "\" champ 1 \ ", \" champ 2 avec \ "quelque chose \" dans ce \ ", \" champ 3 \ ""; undefined > x.match (/^("[^"] * "\ s *, \ s *) * "[^"] * "" [^ "] *" /) null – giacecco

+0

@giacecco, la question posée ici est de rechercher deux doubles guillemets consécutifs ('" "') entre guillemets , ce qui n'est pas ce que vous avez dans votre chaîne de test. – Lucero

+0

vous avez raison et je suis désolé. J'ai été troublé par le fait que d'après le RFC CVS, les doubles-guillemets sont en réalité des CSV valides: c'est la façon dont les guillemets doubles sont censés être échappés http://tools.ietf.org/html/rfc4180#section- 2. Un problème similaire m'a amené ici, mais pas celui d'origine que Mien avait. – giacecco

0

Essayez cette expression régulière:

"(?:[^",\\]*|\\.)*(?:""(?:[^",\\]*|\\.)*)+" 

qui correspondra à une chaîne entre guillemets avec au moins une paire de unescaped guillemets doubles.

2

En raison de la complexité de votre problème, la solution dépend du moteur que vous utilisez. Cela parce que pour le résoudre vous devez utiliser regarder derrière et regarder en avant et chaque moteur n'est pas le même.

Ma réponse utilise le moteur Ruby. La vérification est juste un RegEx mais j'ai tout le code ici pour mieux l'expliquer.

REMARQUE, en raison du moteur Ruby RegEx (ou de ma connaissance), il n'est pas possible de regarder en avant/en arrière en option. J'ai donc besoin d'un petit problème d'espaces avant et après la virgule.

Voici mon code:

orgTexts = [ 
    '"asdf","asdf"', 
    '"", "asdf"', 
    '"asdf", ""', 
    '"adsf", "", "asdf"', 
    '"asdf""asdf", "asdf"', 
    '"asdf", """asdf"""', 
    '"asdf", """"' 
] 

orgTexts.each{|orgText| 
    # Preprocessing - Eliminate spaces before and after comma 
    # Here is needed if you may have spaces before and after a valid comma 
    orgText = orgText.gsub(Regexp.new('\" *, *\"'), '","') 

    # Detect valid character (non-quote and valid quote) 
    resText = orgText.gsub(Regexp.new('([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")'), '-') 
    # resText = orgText.gsub(Regexp.new('([^\"]|(^|(?<=,)|(?<=\\\\))\"|\"($|(?=,)))'), '-') 
    # [^\"]  ===> A non qoute 
    # |   ===> or 
    # ^\"   ===> beginning quot 
    # |   ===> or 
    # \"$   ===> endding quot 
    # |   ===> or 
    # (?<=,)\" ===> quot just after comma 
    # \"(?=,)  ===> quot just before comma 
    # (?<=\\\\)\" ===> escaped quot 

    # This part is to show the invalid non-escaped quots 
    print orgText 
    print resText.gsub(Regexp.new('"'), '^') 

    # This part is to determine if there is non-escaped quotes 
    # Here is the actual matching, use this one if you don't want to know which quote is un-escaped 
    isMatch = ((orgText =~ /^([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")*$/) != 0).to_s 
    # Basicall, it match it from start to end (^...$) there is only a valid character 

    print orgText + ": " + isMatch 
    print 
    print "" 
    print "" 
} 

Lorsqu'il est exécuté les impressions de code:

"asdf","asdf" 
------------- 
"asdf","asdf": false 


"","asdf" 
--------- 
"","asdf": false 


"asdf","" 
--------- 
"asdf","": false 


"adsf","","asdf" 
---------------- 
"adsf","","asdf": false 


"asdf""asdf","asdf" 
-----^^------------ 
"asdf""asdf","asdf": true 


"asdf","""asdf""" 
--------^^----^^- 
"asdf","""asdf""": true 


"asdf","""" 
--------^^- 
"asdf","""": true 

J'espère que je vous donne une idée ici que vous pouvez utiliser avec d'autres moteurs et la langue.

Questions connexes