2008-10-27 12 views
29

Je suis en train de développer un algorithme pour analyser un nombre d'une série de chaînes courtes. Ces chaînes sont quelque peu régulières, mais il y a quelques formes générales différentes et plusieurs exceptions. J'essaye de construire un ensemble de regexes qui manipuleront les diverses formes et exceptions; Je vais les appliquer l'un après l'autre pour voir si je reçois un match.Correspondance d'une sous-chaîne optionnelle dans une expression rationnelle

L'une de ces formes est quelque chose comme ceci:

X (Y) Z 

Où:

  • X est un numéro que je veux saisir.
  • Z est un texte statique prédéfini. c'est essentiellement comment je détermine si cette forme particulière est applicable ou non.
  • Y est une chaîne de longueur et de contenu inconnus entourée de parenthèses.

Egalement: Y est facultatif; il ne semble pas toujours dans une chaîne avec Z et X. Donc, je veux être en mesure d'extraire les numéros de toutes ces chaînes:

  • 10 Z
  • 20 (foo) Z
  • 30 (bar) Z

en ce moment, j'ai un regex qui captera la première:

([0-9]+) +Z 

Mon problème est que je ne sais pas comment construire une regex qui va correspondre à une série de caractères si et seulement s'ils sont entre parenthèses. Cela peut-il être fait dans une seule regex?

Répondre

46
(\d+)\s+(\(.*?\))?\s?Z 

Notez les parenthèses échappées et le? (zéro ou une fois) quantificateurs. Les groupes que vous ne voulez pas capturer peuvent être des groupes (?: Non-capture).

Je suis d'accord sur les espaces. \ s est une meilleure option là-bas. J'ai aussi changé le quantificateur pour m'assurer qu'il y a des chiffres au début. En ce qui concerne les nouvelles lignes, cela dépend du contexte: si le fichier est analysé ligne par ligne, cela ne posera pas de problème. Une autre option consiste à ancrer le début et la fin de la ligne (ajouter un^à l'avant et un $ à la fin).

+0

Les espaces sont statiques. Remplacez-les par \ s + –

+0

ou placez-en un à l'intérieur du()? –

+0

Notez que si l'expression rationnelle capture \ n avec. ou s'il y a plusieurs instances sur une ligne, ceci devrait être non gourmand: (\ d *) (\ (. *? \))? Z – eyelidlessness

2

Essayez ceci:

X (\(Y\))? Z 
7

Vous pouvez faire ceci:

([0-9]+) (\([^)]+\))? Z 

Cela ne fonctionnera pas avec parens imbriqués pour Y, cependant. L'imbrication nécessite une récursivité qui n'est plus strictement régulière (mais sans contexte). Les moteurs d'expressions rationnelles modernes peuvent encore le gérer, bien qu'avec quelques difficultés (références arrières).

+1

Heureusement, je ne pense pas avoir besoin de manipuler des parens imbriquées. –

14

Cela devrait fonctionner:

^\d+\s?(\([^\)]+\)\s?)?Z$ 

ai pas testé bien, mais permettez-moi de vous donner la ventilation, donc s'il y a des bogues restants, ils devraient être assez faciles à trouver:

D'abord le début:

^ = beginning of string 
\d+ = one or more decimal characters 
\s? = one optional whitespace 

Puis cette partie:

(\([^\)]+\)\s?)? 

est en fait:

(.............)? 

Ce qui rend le contenu suivant en option, uniquement si elle existe pleinement

\([^\)]+\)\s? 

\(= an opening bracket 
[^\)]+ = a series of at least one character that is not a closing bracket 
\) = followed by a closing bracket 
\s? = followed by one optional whitespace 

Et la fin est composée de

Z$ 

Z = your constant string 
$ = the end of the string 
Questions connexes