1
votes

Existe-t-il un moyen d'écrire `regex` sans répéter certaines parties?

Je veux faire correspondre Internet. ou Internet à la fin de la chaîne.

Je peux écrire:

$str =~ m/Internet\.|Internet$/

Existe-t-il un moyen d'écrire regex sans répéter Internet?


1 commentaires

Leur regex actuelle permet soit Internet. ou Internet , donc /Internet\.?$/ ne fonctionnerait pas car cela ne correspondrait pas par exemple Internet. Et bien plus. même s'il le faut.


3 Réponses :


7
votes

Vous pouvez utiliser des parenthèses pour regrouper des éléments, et le tube fonctionne localement au sein du groupe.

Cela signifie que vous pouvez transformer ab | ac en a (b | c) . Notez que cela crée également automatiquement un groupe de capture 1 ; si vous ne voulez pas cela, vous pouvez utiliser a(?:b|c).

Donc, dans votre cas, vous pouvez écrire 2 sup >:

$str =~ /Internet(\.|$)/

(Ou /Internet(?:\.|$)/ pour utiliser un groupe non capturant, mais il semble que ce ne soit pas le cas peu importe ici.)


1: Cela signifie que le contenu du groupe correspondant irait dans $ 1 (ou $ 2 , etc. selon le nombre-ième de groupe), donc avec a (b | c) vous obtiendrez soit b ou c dans $1.

2: J'ai supprimé le m parce que c'est de toute façon le mode par défaut pour la correspondance de modèles.

Remarque: Comme mentionné par le commentateur JvdV ci-dessous, en fonction de votre cas d'utilisation vous pouvez également envisager d'ajouter une limite de mot avant le mot Internet . Ensuite, il ne correspondrait qu'à quelque chose comme Internet. ou (Internet.) mais pas IIIIInternet. . Vous feriez cela en utilisant \ b , par exemple /\bInternet(\.|$)/


0 commentaires

4
votes

Tout d'abord, $ ne correspond pas (juste) à la fin de la chaîne. Vous voulez \ z pour cela.


(?: ...) peut être utilisé car les parenthèses sont utilisées en mathématiques. Cela nous permet de factoriser le préfixe commun comme suit:

/
   ^ (?&IDENT) (?: \. (?&IDENT) )* \z

   (?(DEFINE)
      (?<IDENT> [a-zA-Z][a-zA-Z0-9_]* )
   )
/x

En général, nous pouvons utiliser l'interpolation ou DEFINE . P >

Par exemple, regardons la correspondance suivante qui utilise un long motif répété que nous ne pouvons pas simplement éliminer:

my $ident = qr/[a-zA-Z][a-zA-Z0-9_]*/;
/ ^ $ident (?: \. $ident )* \z /x

En utilisant l'interpolation:

XXX

Utilisation de DEFINE (mieux):

/ ^ [a-zA-Z][a-zA-Z0-9_]* (?: \. [a-zA-Z][a-zA-Z0-9_]* )* \z /x

Il y a toujours une répétition, mais au lieu de répéter un modèle complexe, nous répétons un mot simple et les fautes d’orthographe entraîneront une erreur fatale plutôt qu’une mauvaise conduite potentiellement subtile.


2 commentaires

Pourquoi utiliser DEFINE " mieux " - parce qu'il n'y a pas besoin d'une variable supplémentaire alors, ou y a-t-il encore d'autres raisons? (Efficacité?)


@zdim, Parce que l'autre manière compile le modèle, le stringifie, puis le recompile. (Ce n'est que si le motif entier est une var que la stringification et la recompilation sont évitées.) Et bien sûr, il doit vérifier si $ ident a changé si vous appelez la correspondance dans une boucle.



0
votes

En fonction de votre entrée, il peut arriver au début / au milieu / à la fin du contenu. Il serait donc préférable d'utiliser le code ci-dessous pour éviter la casse:

$str =~ m/[Ii]nternet(\.|$)/
or
$str =~ m/Internet(\.|$)/i

De plus, si vous souhaitez stocker dans le groupe, utilisez des parenthèses.


0 commentaires