Expression régulière pour rechercher des guillemets non échappés dans un fichier CSV

StackOverflow https://stackoverflow.com/questions/1601780

  •  05-07-2019
  •  | 
  •  

Question

Que serait une expression rationnelle pour trouver des ensembles de 2 guillemets doubles non échappés contenus dans des colonnes séparées par des guillemets dans un fichier CSV?

Pas un match:

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

Correspondance:

"asdf""asdf", "asdf"
"asdf", """asdf"""
"asdf", """"
Était-ce utile?

La solution

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

Donc, en clair: "ne correspond à deux guillemets successifs, que s'ils NE SONT PAS précédés d'une virgule ou d'une fin de ligne, avec éventuellement des espaces et des tabulations entre les" .

(i) en plus d'être les méta-caractères normaux de début de chaîne et de fin de chaîne .

Autres conseils

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

Ma réponse utilise le moteur Ruby. La vérification n’est qu’un seul RegEx mais j’ai sorti tout le code ici pour mieux l’expliquer.

REMARQUE: en raison du moteur Ruby RegEx (ou à ma connaissance), il est impossible de regarder en avant ou en arrière. 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 ""
} 

Une fois exécuté, le code est imprimé:

"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 vous donner une idée de ce que vous pouvez utiliser avec un autre moteur et une autre langue.

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

devrait fonctionner, je suppose ...

Pour les correspondances sur une seule ligne:

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

ou pour multiligne:

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

Éditer / Remarque: En fonction du moteur d’expression régulière utilisé, vous pouvez utiliser des recherches et d’autres éléments pour alléger l’expression régulière. Mais cela devrait fonctionner dans la plupart des moteurs de regex.

Essayez cette expression régulière:

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

Cela fera correspondre toute chaîne entre guillemets avec au moins une paire de guillemets doubles non échappés.

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