Effectivement non, un moteur de regex ne sait faire qu'une seule chose: trouver des motifs dans une chaîne. Il n'a pas vocation à faire des calculs ne serait ce qu'un simple compteur et ce n'est pas son rôle. Ce rôle revient éventuellement aux fonctions qui l'utilisent.
D'autre part la notion de "regex en général" n'existe pas, de même que la "pattern portable", c'est juste une vieille croyance répandue. Les patterns sont intrinsèquement liées aux moteurs qui vont les utiliser, que ce soit par les outils dont elles disposent, par leurs syntaxes, par la manière dont elles sont construites et vont être traitées (Une même pattern peut donner un résultat différent avec deux moteurs). Pour faire le grand écart, tu pourrais comparer par exemple les patterns utilisées par l'outil sed en mode POSIX BRE (Basic Regular Expression) avec les patterns plus sophistiquées des moteurs de Perl ou de .net.
Pour ce qui est d'une éventuelle ruse pour compter quand même, autre qu'une fonction native d'un langage renvoyant directement le nombre d'occurrences, il n'y a pas de solution 100% pur porc qui ne mettrait en jeu que la machine bête et méchante qui cherche ses tokens dans sa chaîne:
Le moteur de Perl permet d'exécuter dynamiquement du code du code au sein même d'une pattern avec la syntaxe (?{ code }). Ça reste donc extrêmement lié au langage. Et de toute manière, si c'est juste pour compter des occurrences, il y a plus simple.
De même le moteur PCRE peut effectuer un appel de fonction en cours de pattern (le callout) avec la syntaxe (?Cn) ou n est un entier (0-255) associé à la fonction en question. Cette possibilité n'est pas implémentée en PHP, R ou dans les éditeurs comme notepad++ ou sublimetext, mais elle est disponible dans autoHotKey, QuickMacro et est utilisée à des fins de débogage par l'outil pcretest.
Une solution consiste à intervenir auparavant sur la chaîne cible en lui ajoutant artificiellement un compteur prêt à l'emploi (évidemment ça ne sert à rien, mais on peut le faire). On ajoute une ligne à la fin de la chaîne:
1 2
| abc11
#1#2#3#4#5#6#7#8#9#10#11#12#13#14#15#... |
Puis on utilise une pattern (PCRE/PERL ici mais elle doit pouvoir s'adapter bon an mal an pour Java) du type:
(?:[^0-9]*[0-9](?=(?:.*\R)++(?|(?>#[0-9]+)*?#\1#([0-9]+)|#(1)#)))+(?s).*\K\1|0
Ici j'ai utilisé une ligne-compteur imaginaire et infinie, mais avec un peu d'astuce, il est peut être possible d'utiliser juste les dix chiffres et de le faire compter en base 10.
(Le groupe non-capturant est répété à chaque chiffre. À l'intérieur du lookahead, pour la première occurrence on va capturer le chiffre 1 dans la "ligne compteur", puis pour les occurrences suivantes on prend le nombre qui suit la capture précédente \1.)
On peut aussi faire quelque chose du même goût avec le système de pile du moteur .net:
(?<stk>[^0-9]*[0-9](?=.*\n))+(?>(?:.*\n)*)(?>#(?<-stk>(?<result>[0-9]+)))*
Partager