11
votes

C #, expressions régulières: comment analyser les valeurs séparées par des virgules, lorsque certaines valeurs peuvent être citées elles-mêmes contenant des virgules

in c #, en utilisant la classe regex code>, comment analysez-vous des valeurs séparées par des virgules, lorsque certaines valeurs peuvent être citées elles-mêmes contenant des virgules?

0       cat
1       dog
2       0 = OFF, 1 = ON
3       lion
4       tiger
5       R = red, G = green, B = blue
6       bear


1 commentaires

Plutôt que de commencer par la solution - des expressions régulières - et d'essayer d'y appliquer le problème, envisagez d'aller dans l'autre sens. Commencez avec le problème et choisissez l'outil qui le résout clairement bien. Personnellement, je résoudrais ce problème en écrivant un Lexer pour votre langue. Ce code est susceptible d'être plus clair, compréhensible, débisible et extensible que le bruit de la ligne de modem qui est une expression régulière.


9 Réponses :


24
votes

Essayez avec cette regex:

    Regex regexObj = new Regex(@"""[^""\r\n]*""|'[^'\r\n]*'|[^,\r\n]*");
    Match matchResults = regexObj.Match(input);
    while (matchResults.Success) 
    {
        Console.WriteLine(matchResults.Value);
        matchResults = matchResults.NextMatch();
    }
  • CAT LI>
  • chien li>
  • "0 = off, 1 = sur" li>
  • lion li>
  • tigre li>
  • 'r = rouge, g = vert, b = bleu' li>
  • ours li> ul>

    Note: strong> Cette solution de regex fonctionnera pour votre cas, mais je vous recommande d'utiliser une bibliothèque spécialisée comme FIGEHELPERS . P> P>


7 commentaires

Pour moi, votre dernière réponse modifiée donne la sortie suivante: 0 chat 1 2 chien 3 4 "0 = off, 1 = sur" 5 6 lion 7 8 Tiger 9 10 'r = rouge, g = vert, b = bleu "11 12 ours 13


@CMS: J'ai pu avoir votre idée de travailler pour moi, mais je devais faire une petite modification (remplaçant * par + à la fin). Mon regex est ... nouvelle regex (@ "" "" "\ r \ n] *" "| '' '' '[^' \ r \ n] * '| [^, \ r \ n] +")


Presque oublié: merci, CMS et d'autres pour votre précieuse contribution.


Whoops ... a parlé trop tôt ... ma "solution" ne fonctionne pas quand certains champs sont "vides" ... Voir, par exemple, les deux virgules consécutives suivant Cat: "Cat , Dog, \" 0 = Off , 1 = sur \ ", lion, tigre, 'r = rouge, g = vert, b = bleu', ours"


Le CSV n'est pas régulier - les regexes jamais puissent analyser tous les fichiers CVS valides. comme toujours. C'est une folie sauf comme un hack sale ...


Voici ce que j'ai enfin installé sur ... String Regexstring = "" + "((? <= \") [^ \ "] * (? = \")) "//" ... "+" | ((? <= \ ') [^ \'] * (? = \ ')) "//" ... ... "+" | (^ [^,] * (? = ,))) "/// ^ ... ..., +" | ((? <=,) [^,] * $) "//, ..." $ + "| (? < =,). {0} (? =,) "// , +" | (? <=,) ([^ \ "\ ']. *?)" //, ... (à l'exclusion «') à ...,; regex regex = nouvelle regex (regexstring);


@Jaysonfix diriez-vous de poster cette solution dans votre question? J'ai exactement le même problème et votre solution est un peu difficile à lire dans un commentaire comme ça.



8
votes

Ce n'est pas une regex, mais j'ai utilisé Microsoft.visalbasic.fileio.texalbasicparser pour accomplir cela pour les fichiers CSV. Oui, cela pourrait se sentir un peu étrange ajouter une référence à Microsoft.visualbasic dans une application C #, peut-être même un peu sale, mais bon cela fonctionne.


1 commentaires

+1 Excellente solution dans mon cas. Il est installé avec le cadre afin qu'aucun des assemblages supplémentaires n'ajoutez à l'installateur et sans groupe de fichiers source supplémentaire pour une tâche simple.



22
votes

Pourquoi ne pas tenir compte des conseils des experts et Ne roule pas votre propre analyseur CSV .

Votre première pensée est: "Je dois manipuler des virgules à l'intérieur des citations."

Votre prochaine pensée sera: «Oh, merde, j'ai besoin de gérer des citations à l'intérieur des citations. Quotes échappés. Doubles citations. Citations simples ..."

C'est une route de la folie. N'écrivez pas le vôtre. Trouvez une bibliothèque avec une couverture de test d'unité étendue qui frappe toutes les parties durs et a traversé l'enfer pour vous. Pour .NET, utilisez la source gratuite et open source bibliothèque FichierHelPers .


4 commentaires

C'était ma première pensée aussi.


Une autre raison: la spécification CSV est en fait étonnamment complexe, compte tenu de toutes les différentes manières de citer et de délimiter les valeurs. Sans parler du fait qu'il n'est pas en fait une spécification pour le CSV ... (il y a RFC4180, mais cela indique explicitement que ce n'est qu'une "tentative" à une spécification commune et que les implémentations réelles varient. ) Les chances sont donc, si vous vous lancez le vôtre, vous le ferez mal.


J'ai trouvé que Csvhelper fonctionne bien et c'est dans Nuget ( Joshclose.github.io/csvhelper ). Il est sous licence MS-Pl, qui est moins effrayante que la bibliothèque de fichiers sous licence LGPL si vous avez un produit commercial.


Après avoir découvert que ce n'était pas une annonce, mais une bibliothèque sérieuse, j'ai constaté que prenant les extraits dont j'avais besoin et que j'utilisais, je me plaisait la meilleure solution: la plus petite bibliothèque de ce dont j'avais besoin et de Code fiable lors de l'utilisation de fichiersHelPers.



8
votes

ah, regex. Maintenant, vous avez deux problèmes. ;)

J'utiliserais un tokenizer / analyseur, car il est assez simple, et plus important encore, beaucoup plus facile de lire pour la maintenance ultérieure.

Ceci fonctionne, par exemple: < Pré> xxx


2 commentaires

Il y a un bogue dans cette mise en œuvre. Dans ienumerator méthode getenumerator (), vous devez ajouter "si (valeur.length> 0) {retour retour nouveau jeton (TokenType.value, valeur.tostring ());}" Dans la boucle TOUT, à la fin. . Sinon, vous manquez le jeton final


Merci @dpan, corrigé



2
votes

Fonction: xxx

utilisation xxx

sortie: xxx


0 commentaires

4
votes

CSV n'est pas régulier . À moins que votre langue regex ait suffisamment de puissance pour gérer la nature stalière de l'analyse de la CSV (improbable, la MS One ne le fait pas), toute solution pure regex est une liste de bogues en attente de se produire lorsque vous avez touché une nouvelle source d'entrée qui n'est pas Assez géré par la dernière regex.

La lecture du CSV n'est pas si complexe d'écrire en tant que machine d'état puisque la grammaire est simple, mais vous devez même que vous devez envisager: citations citations, virgules dans des citations, de nouvelles lignes dans des guillemets, des champs vides.

En tant que tel, vous devriez probablement utiliser l'analyseur CSV de quelqu'un d'autre. Je recommande CSVREADER pour .NET


0 commentaires

7
votes

Il suffit d'ajouter la solution que j'ai travaillé ce matin.

2,3.03,"Hello, my name is ""Joshua""",A,B,C,,,D


2 commentaires

@Joshua, c'est la meilleure regèt de fractionner une chaîne que j'ai trouvée. Et j'ai essayé assez quelques-uns. La magie semble être au (? <= ^ |,) partie. La plupart des solutions similaires ont : ^ plutôt que <= ^ . Les autres solutions seront incorrectes pour ", 1", le réduire à une correspondance de 2, l'identifie correctement. 3. Merci.


C'est une solution fantastique.



1
votes

J'ai trouvé quelques bugs dans cette version, par exemple une chaîne non citée qui dispose d'une seule citation de la valeur.

Et je suis d'accord Utilisez la bibliothèque FileHelper lorsque vous pouvez, mais cette bibliothèque nécessite que vous sachiez quoi Vos données ressembleront à ... J'ai besoin d'un analyseur générique.

J'ai donc mis à jour le code ci-après et je pensais que je partageais ... xxx


1 commentaires

Trouvé des bugs dans quelle version ? Les réponses n'apparaissent pas dans une commande correcte, donc si vous souhaitez faire référence à une autre réponse, il est préférable de le lier directement. Le bouton partager ci-dessous La réponse fournit l'URL appropriée.