Comment parsingr une chaîne délimitée par des virgules lorsque la virgule et la parenthèse existent dans le champ

J’ai cette chaîne en C #

adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO 

Je veux utiliser un RegEx pour l’parsingr afin d’obtenir les éléments suivants:

 adj_con(CL2,1,3,0) adj_cont(CL1,1,3,0) NG NG/CL 5 value of CL(JK) HO 

En plus de l’exemple ci-dessus, j’ai testé les éléments suivants, mais je ne parviens toujours pas à l’parsingr correctement.

 "%exc.uns: 8 hours let @ = ABC, DEF", "exc_it = 1 day" , " summ=graffe ", " a,b,(c,d)" 

Le nouveau texte sera dans une chaîne

 ssortingng mystr = @"""%exc.uns: 8 hours let @ = ABC, DEF"", ""exc_it = 1 day"" , "" summ=graffe "", "" a,b,(c,d)"""; 

     ssortingng str = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO"; var resultSsortingngs = new List(); int? firstIndex = null; int scopeLevel = 0; for (int i = 0; i < str.Length; i++) { if (str[i] == ',' && scopeLevel == 0) { resultStrings.Add(str.Substring(firstIndex.GetValueOrDefault(), i - firstIndex.GetValueOrDefault())); firstIndex = i + 1; } else if (str[i] == '(') scopeLevel++; else if (str[i] == ')') scopeLevel--; } resultStrings.Add(str.Substring(firstIndex.GetValueOrDefault())); 

    Evénement plus rapide:

     ([^,]*\x28[^\x29]*\x29|[^,]+) 

    Cela devrait faire l’affaire. Fondamentalement, recherchez soit une “empreinte de fonction” ou quelque chose sans virgule.

     adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO ^ ^ ^ ^ ^ 

    Les carets symbolisent l’endroit où s’arrête le groupement.

    Juste cette regex:

     [^,()]+(\([^()]*\))? 

    Un exemple de test:

     var s= "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO"; Regex regex = new Regex(@"[^,()]+(\([^()]*\))?"); var matches = regex.Matches(s) .Cast() .Select(m => m.Value); 

    résultats

     adj_con(CL2,1,3,0) adj_cont(CL1,1,3,0) NG NG/CL 5 value of CL(JK) HO 

    Si vous devez simplement utiliser Regex, vous pouvez diviser la chaîne comme suit:

     , # match a comma (?= # that is followed by (?: # either [^\(\)]* # no parens at all | # or (?: # [^\(\)]* # ... \( # ( [^\(\)]* # stuff in parens \) # ) [^\(\)]* # ... )+ # any number of times )$ # until the end of the ssortingng ) 

    Il divise votre consortingbution en ce qui suit:

     adj_con(CL2,1,3,0) adj_cont(CL1,1,3,0) NG NG/CL 5 value of CL(JK) HO 

    Vous pouvez également utiliser les constructions de regroupement équilibrées de .NET pour créer une version qui fonctionne avec des parenthèses nestedes, mais vous êtes probablement aussi à l’aise avec l’une des solutions autres que Regex.

    Une autre façon de mettre en œuvre ce que Snowbear faisait:

      public static ssortingng[] SplitNest(this ssortingng s, char src, ssortingng nest, ssortingng trg) { int scope = 0; if (trg == null || nest == null) return null; if (trg.Length == 0 || nest.Length < 2) return null; if (trg.IndexOf(src) >= 0) return null; if (nest.IndexOf(src) >= 0) return null; for (int i = 0; i < s.Length; i++) { if (s[i] == src && scope == 0) { s = s.Remove(i, 1).Insert(i, trg); } else if (s[i] == nest[0]) scope++; else if (s[i] == nest[1]) scope--; } return s.Split(trg); } 

    L'idée est de remplacer tout délimiteur non nested par un autre délimiteur que vous pouvez ensuite utiliser avec une ssortingng.Split() ordinaire.Split ssortingng.Split() . Vous pouvez également choisir le type de crochet à utiliser - () , <> , [] ou même quelque chose d'étrange comme \/ , ][ ou `' . Pour vos besoins, vous utiliseriez

     ssortingng str = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO"; ssortingng[] result = str.SplitNest(',',"()","~"); 

    La fonction transformerait d'abord votre chaîne en

     adj_con(CL2,1,3,0)~adj_cont(CL1,1,3,0)~NG~ NG/CL~ 5 value of CL(JK)~ HO 

    puis divisé sur le ~ , en ignorant les virgules nestedes.

    En supposant que les parenthèses ne soient pas nestedes, vous pouvez facilement faire correspondre les jetons souhaités au lieu de scinder la chaîne:

     MatchCollection matches = Regex.Matches(data, @"(?:[^(),]|\([^)]*\))+"); 
     var s = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO"; var result = ssortingng.Join(@"\n",Regex.Split(s, @"(?<=\)),|,\s")); 

    Le modèle correspond à) et l'exclut de la correspondance, puis correspond, ou correspond, suivi d'un espace.

    résultat =

    adj_con (CL2,1,3,0)
    adj_cont (CL1,1,3,0)
    NG
    NG / CL
    5 valeur de CL (JK)
    HO

    La classe TextFieldParser ( msdn ) semble avoir la fonctionnalité intégrée:

    TextFieldParser Class: – Fournit des méthodes et des propriétés pour l’parsing de fichiers texte structurés.

    L’parsing d’un fichier texte avec TextFieldParser est similaire à une itération sur un fichier texte, tandis que la méthode ReadFields pour extraire des champs de texte est similaire à la division des chaînes.

    TextFieldParser peut parsingr deux types de fichiers: délimité ou largeur fixe. Certaines propriétés, telles que Delimiters et HasFieldsEnclosedInQuotes, n’ont de sens que si vous travaillez avec des fichiers délimités, tandis que la propriété FieldWidths n’a de sens que si vous travaillez avec des fichiers à largeur fixe.

    Voir l’ article qui m’a aidé à trouver que

    Voici une option plus puissante, qui parsing l’ensemble du texte, y compris les parenthèses nestedes:

     ssortingng pattern = @" \A (?> (? (?: [^,()] # Regular character | (? \( ) # Opening paren - push to stack | (?<-Paren> \) ) # Closing paren - pop | (?(Paren),) # If inside parentheses, match comma. )*? ) (?(Paren)(?!)) # If we are not inside parentheses, (?:,|\Z) # match a comma or the end )*? # lazy just to avoid an extra empty match at the end, # though it removes a last empty token. \Z "; Match match = Regex.Match(data, pattern, RegexOptions.IgnorePatternWhitespace); 

    Vous pouvez obtenir tous les matchs en match.Groups["Token"].Captures .