2
votes

Regex (PCRE): correspond à tous les chiffres sous réserve de la présence d'une chaîne

En utilisant PCRE, je souhaite capturer uniquement et tous les chiffres sur une seule ligne, mais uniquement si une certaine chaîne (disons "STRING99") est présente n'importe où dans cette ligne.

Par exemple, considérons ces deux cas:

a1 STRING99 2b c3d

a1 2b c3d

Dans le premier cas, je veux que le résultat soit "19923". Dans le second cas, je veux un résultat vide.

Je ne suis pas sûr que cela soit possible. Cela peut fonctionner avec un look-back de longueur variable, mais cela n'est pas pris en charge dans PCRE. De plus, quelque chose comme (?=.*STRING99.*$)(\D|(\d))* fonctionnera, mais "un groupe de capture répété ne capturera que la dernière itération", ce qui signifie que le deuxième groupe de capture ne capture que la dernière chiffre. Je ne parviens pas à trouver une solution de contournement pour cela.

(Ce n'est évidemment pas difficile à réaliser avec 2 opérations Regex consécutives, mais je le veux dans une formule.)


0 commentaires

3 Réponses :


1
votes

Nous pourrions utiliser un remplacement de regex avec une fonction de rappel:

$output = preg_replace_callback('/^.*\bSTRING99\b.*$/', function ($match) {
    return preg_replace("/\D+/", "", $match[0]);
}, 'a1 STRING99 2b c3d');

echo $output;   // prints 1992

L'approche ici consiste d'abord à faire correspondre uniquement les entrées contenant STRING 99 . Ensuite, sur une telle correspondance, nous supprimons tous les caractères non numériques. Les non-matches n'auraient pas ce remplacement effectué.


1 commentaires

Je n'ai pas pu essayer cette méthode car je ne travaille pas réellement en PHP mais uniquement en utilisant PCRE dans Autohotkey. Merci, cependant, d'avoir proposé cette approche alternative.



1
votes

Vous pouvez utiliser

(?:\G(?!^)|^(?=.*STRING99)|^.*(*ACCEPT))\d*\K\D+

Voir la démo regex (où j'ai remplacé \D par [^\d\n] à des fins de démonstration uniquement puisque le test est effectué sur une chaîne multiligne).

Détails

  • (?:\G(?!^)|^(?=.*STRING99)|^.*(*ACCEPT)) - soit la fin de la précédente correspondance réussie ( \G(?!^) ) Ou ( | ) la position de début de la chaîne si après n'importe quel 0+ caractères, il y a une chaîne STRING99 (voir ^(?=.*STRING99) ) ou (sinon) la chaîne entière correspond à ^.* et la correspondance réussie est renvoyée (le modèle n'est pas analysé plus loin)
  • \d* - 0 chiffres ou plus sont consommés
  • \K - et supprimé de la mémoire tampon de correspondance
  • \D+ - 1 ou plusieurs caractères non numériques (qui seront éventuellement supprimés).


2 commentaires

Merci! Cette solution semble également fonctionner correctement.


@Logitope Heureux que cela ait fonctionné pour vous. Veuillez également envisager de voter pour si ma réponse vous a été utile (voir Comment voter pour Stack Overflow? ), Car vous avez droit au privilège de vote positif après avoir atteint 15 points de répétition. Notez que vous pouvez voter pour toutes les réponses qui se sont avérées utiles.



1
votes

Vous pouvez utiliser cette regex PCRE dans preg_replace :

$repl = preg_replace('~^(?!.*STRING99).*(*SKIP)|\D+~', '', $str);

Démo RegEx

Détails RegEx:

  • ^ : Démarrer
  • (?!.*STRING99) : Lokahead pour vérifier si nous avons STRING99 n'importe où en entrée
  • .*(*SKIP) : correspond au reste de l'entrée jusqu'à la fin et ignore-le
  • | : OU
  • \D+ : correspond à 1+ sans chiffre

Code PHP:

^(?!.*STRING99).*(*SKIP)|\D+


1 commentaires

C'est une solution élégante. De plus (*SKIP) serait omis.