1
votes

Existe-t-il un moyen de réutiliser une partie d'un modèle dans une expression régulière C ++?

Je veux voir si une séquence est (conditionnellement) entourée de quelque chose.

Exemple de cas 1 - cat avec l'option d'être entouré de crochets.

1.5 // -> matches
.0  // -> matches
1.  // -> matches
50. // -> matches
2   // -> doesn't match
.   // -> doesn't match

\\ [? cat \\ ]? semble être la solution regex, mais cela correspond également de manière indésirable pour [cat et cat] !

Je pourrais utiliser cat | \\ [cat \\] pour traiter les deux cas individuellement. Mais je devais juste écrire l'expression cat deux fois.

Au lieu de cela, mon objectif serait de refléter en quelque sorte le comportement ? (une ou zéro occurrence) sur les expressions \\ [ et \\] .

Existe-t-il donc un moyen de traiter deux (ou plus) expressions comme une unité et réfléchir à cela dans une seule expression régulière?


Disons que pour le cas 2, je veux vérifier les nombres à virgule flottante. C'est une situation similaire:

un . entouré d'au moins 1 chiffre.

[cat] // -> matches
cat   // -> matches

Dans ce cas, je voudrais refléter le comportement + (au moins une occurrence) sur les sections à deux chiffres. Mais je ne sais pas comment et les seules façons que je connais actuellement pour résoudre ce problème ne semblent tout simplement pas optimales:

  • fractionnement de l'expression régulière en sections OR
  • deux exécutions de regex (vérifie d'abord si l'expression est un seul point)
  • capture et comptage du nombre de caractères correspondants. ( std :: smatch )

Je ne veux vraiment pas faire cela car dans mon programme réel, mes chaînes actuelles sont très compliquées et contiennent des sous-expressions qui suivent ces modèles dans le modèle lui-même. S'il y a un moyen de résoudre ce problème avec une seule expression régulière, je pourrais éviter un énorme désordre de code.


1 commentaires

Utilisez des sous-routines regex avec boost :: regex ou créez simplement le modèle regex dynamiquement.


3 Réponses :


1
votes

Le problème avec les expressions régulières est qu'elles ne sont pas terminées, vous devez donc pirater pour obtenir des choses intelligentes comme celle-ci.

Pour votre:

un . entouré d'au moins 1 chiffre.

commencez par rechercher:

[^0-9]\.[^0-9]

générant une erreur pour tout ce qui ne correspond pas, puis recherchez le négatif:

[0-9]*\.[0-9]*

et génère une erreur si cela correspond.


6 commentaires

bien, mais maintenant "abc" ou "5" ne correspondraient pas et donc passeraient, même s'ils ne sont pas des nombres de pointeurs flottants. Je serais obligé d'effectuer un deuxième contrôle. Ensuite, deux regex s'exécute (vérifie d'abord si l'expression est un seul point) semble m'y amener en premier lieu.


@StackDanny C'est maintenant corrigé et "abc" ou "5" ne correspondra pas.


L'élément clé qui permet à cela de fonctionner est que \. reste positif dans les deux sens. Donc, comme je l'ai dit, il vous suffit de chercher un seul \. en premier lieu et d'y arriver sans avoir à inverser les choses.


@StackDanny Vraiment difficile de garder une trace de ce que vous demandez exactement puisque vous continuez à déplacer les poteaux d'objectifs. :(


ce dont j'ai besoin ici est de refléter le comportement + (au moins une occurrence) sur les sections à deux chiffres. Dommage que cela ne fonctionne pas. J'apprécie que vous partagiez vos idées sur le sujet, merci!


@PaulEvans OP a clairement demandé comment NE PAS répéter une partie répétitive d'un motif dans une regex. Vous ne résolvez pas le problème en essayant de suggérer un modèle alternatif pour un exemple de problème OP utilisé comme vitrine pour la fonctionnalité recherchée par OP.



1
votes

Pour répéter un modèle en C ++ lors de l'utilisation de boost :: regex , il est possible d'utiliser sous-routines regex : capturez un motif que vous devez répéter et utilisez (? n) où n est l'ID du groupe de capture. Utilisez (? R) pour répéter le modèle entier.

Exemple :

std::string s{"This is a cat"};
std::string block{"cat"};
std::smatch what;
std::regex expr{"\\[" + block + "\\]|" + block};
if (std::regex_search(s, what, expr))
{
  std::cout << what[0] << '\n';
}

std :: regex ne le permet pas. Vous devez créer des modèles de manière dynamique:

std::string s{"This is a cat"};
boost::smatch what;
boost::regex expr{R"~(\[(cat)\]|(?1))~"};
if (boost::regex_search(s, what, expr))
{
  std::cout << what[0] << '\n';
}

Voir cette démo C ++ .


1 commentaires

Cela semble prometteur. Merci. Il est triste qu'une étape aussi fondamentale vers l'exhaustivité du turing ne soit pas disponible pour std :: regex



0
votes

Un autre essai en utilisant lookaround pour vérifier la longueur afin d'éviter les correspondances indésirables.

^(?=.{2,})[0-9]*\.[0-9]*$

Démo: https://regex101.com/r/VMgKL5/3


1 commentaires

Idée intelligente, malheureusement cela ne fonctionne que pour les cas où l'expression à l'intérieur a une longueur attendue constante.