Regex: groupes de capture répétés

je dois analyser quelques tableaux à partir d'un fichier texte ASCII. Voici un échantillon partiel:

QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212
RECKITTBEN  192.50  209.00  192.50  201.80    5.21      34      2850     5.707
RUPALIINS   150.00  159.00  150.00  156.25    6.29       4        80      .125
SALAMCRST   164.00  164.75  163.00  163.25    -.45      80      8250    13.505
SINGERBD    779.75  779.75  770.00  773.00    -.89       8        95      .735
SONARBAINS   68.00   69.00   67.50   68.00     .74      11      3050     2.077

le tableau se compose d'une colonne de texte et de 8 colonnes de nombres à virgule flottante. J'aimerais capturer chaque colonne via regex.

je suis plutôt nouveau dans les expressions régulières. Voici le modèle de regex défectueux que j'ai inventé:

(S+)s+(s+[d.-]+){8}

mais le motif ne saisit que la première et la dernière colonne. RegexBuddy émet également l'avertissement suivant:

vous avez répété le groupe de capture m'. Le groupe capturera seulement la dernière itération. Mettre une capture d' groupe autour du groupe répété à capturez toutes les itérations.

j'ai consulté leur fichier d'aide, mais je ne sais pas comment résoudre cela.

Comment capturer chaque colonne séparément?

10
demandé sur johnnyRose 2010-07-03 23:35:35

3 réponses

en C# (modifié de cet exemple ):

string input = "QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212";
string pattern = @"^(\S+)\s+(\s+[\d.-]+){8}$";
Match match = Regex.Match(input, pattern, RegexOptions.MultiLine);
if (match.Success) {
   Console.WriteLine("Matched text: {0}", match.Value);
   for (int ctr = 1; ctr < match.Groups.Count; ctr++) {
      Console.WriteLine("   Group {0}:  {1}", ctr, match.Groups[ctr].Value);
      int captureCtr = 0;
      foreach (Capture capture in match.Groups[ctr].Captures) {
         Console.WriteLine("      Capture {0}: {1}", 
                           captureCtr, capture.Value);
         captureCtr++; 
      }
   }
}

sortie:

Matched text: QSMDRYCELL   11.00   11.10   11.00   11.00    -.90      11     11000     1.212
...
    Group 2:      1.212
         Capture 0:  11.00
         Capture 1:    11.10
         Capture 2:    11.00
...etc.
13
répondu Tim Pietzcker 2010-07-03 19:58:24

Malheureusement, vous devez répéter le (…) 8 fois pour obtenir chaque colonne séparément.

^(\S+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)$

si le code est possible, vous pouvez d'abord faire correspondre ces colonnes numériques dans leur ensemble

>>> rx1 = re.compile(r'^(\S+)\s+((?:[-.\d]+\s+){7}[-.\d]+)$', re.M)
>>> allres = rx1.findall(theAsciiText)

puis diviser les colonnes par des espaces

>>> [[p] + q.split() for p, q in allres]
4
répondu kennytm 2010-07-03 19:48:06

si vous voulez savoir à quoi sert l'avertissement, c'est parce que votre groupe de capture correspond à plusieurs fois (8, comme vous l'avez spécifié) mais la variable de capture ne peut avoir qu'une seule valeur. On lui attribue la dernière valeur appariée.

comme décrit dans question 1313332 , récupérer ces correspondances multiples n'est généralement pas possible avec une expression régulière, Bien que .NET et Perl 6 aient un certain support pour cela.

le avertissement suggère que vous pourriez mettre un autre groupe autour de l'ensemble, comme ceci:

(\S+)\s+((\s+[\d\.\-]+){8})

vous pourriez alors voir toutes les colonnes, mais bien sûr elles ne seraient pas séparées. Comme il n'est généralement pas possible de les capturer séparément, l'intention la plus courante est de tout capturer, et l'avertissement aide à vous le rappeler.

4
répondu Sam Brightman 2017-05-23 12:09:14