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?
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.
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]
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.