2009-12-04 5 views
0

En What regular expressions can never match?/$./ a été donné en réponse. J'ai joué un peu avec ça et j'ai découvert que les deux lignes de code suivantes généraient des résultats différents. Les deuxièmes correspondances, mais la première ne le fait pas. Quelqu'un peut-il expliquer pourquoi?

$ printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m' 
$ perl -0777 -e '$_="a\nb\n"; print if m/$./m' 

Notez également que l'ajout <> dans ce qui suit provoque le match à l'échec:

$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m' 
$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m' 

(C'est, les premières impressions '1', la seconde imprime une ligne vide)

Répondre

9

Activation des avertissements donne un indice sur la raison:

 
$ printf 'a\nb\n' | perl -0777 -w -e 'use feature qw/say/; $b = "a\nb\n"; say $b =~ m/$./m' 
Use of uninitialized value $. in regexp compilation at -e line 1. 
1 

Vous utilisez une valeur non définie dans l'expression rationnelle. La séquence $. refers to the special variable for the line number of the last-accessed file handle. Il ne pas désigner l'expression régulière pour "fin de ligne suivie de n'importe quel caractère." Puisque vous n'avez accédé à aucun fichier, c'est toujours undef, donc l'expression rationnelle est vide. Lorsque vous utilisez l'option -n, il encapsule effectivement le reste du programme dans while (<>) { ... }, de sorte que vous avez lu <> et se termine par 1 dans $. parce que vous avez lu une ligne.

Lorsque vous dites <> lors de la deuxième tentative, vous avez accédé au descripteur de fichier stdin. L'expression régulière est maintenant m/1/m, ce qui ne correspond pas à la chaîne d'entrée.

+1

Vous pouvez utiliser' -E' au lieu de '-e' qui fait la même chose que -e'use feature ': 5.10'' =>' perl -0777 -wE '$ b = "a \ nb \ n"; dis $ b = ~ m /$./ m'' –

+0

@Brad: Merci pour l'indice '-E'! –

5

Ce code imprime un "tuyau cassé" pour moi, car perl n'attend aucune entrée ici. Il utilise également la variable indéfinie $. (vous verrez si vous allez ajouter -w passer à perl). Cette variable $. représente le numéro de la ligne en cours, puis la lecture des lignes par <...>. Voilà pourquoi il est pas défini dans cet exemple:

## matching pattern will look like m//m 
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m' 

code suivant lit les données de conduite, mais ne correspond pas à cause $. est devenu égal à 1 après <>. Et le modèle correspondant est devenu m/1/m:

## matching patter will be m/1/m, which is not found in $b value 
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m' 

Mise à jour:

Utilisez m'$.'m ou m/$ ./mx (merci à Michael Carman) pour désactiver l'interpolation de variables.

+0

Bien sûr! Variable spéciale '$ .'! Comment écrirait-on l'expression rationnelle, alors? En utilisant 'm '$.' '? –

+0

@JB: oui, 'm '$.'' Est une bonne idée –

+0

'/\$./' analyse comme "literal '$' suivi de n'importe quel caractère" Vous pouvez utiliser le modificateur '/ x' pour les séparer, cependant: 'm/$./x' –

0

Dans le premier cas, je crois que c'est à cause du commutateur -n. En d'autres termes

printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m' 

Causes $ _ pour obtenir la valeur a\n la première fois dans la boucle et b\n la deuxième fois clairement qui ne correspondent pas. Alors que/m $ correspond au \ n dans le second exemple, c'est pourquoi cela correspond.

Avec ces deux derniers exemples, je travaille encore :)

Edit: Wow j'avais que complètement faux, et je pense que vous aussi. Le problème est que m/$./m est et non une fin de ligne suivie d'un caractère générique, mais plutôt la variable $. interpolé comme une expression régulière. Yikes!

6

Le $. dans votre expression régulière est analysé comme la valeur de la variable spéciale $. ($INPUT_LINE_NUMBER) plutôt que comme "fin de ligne suivie de n'importe quel caractère".

Notez également que le modificateur /m modifie la signification de $ de correspondance à la fin de la chaîne pour correspondre à une fin de ligne n'importe où dans la chaîne. Voir Modifiers en perlre. Cela signifie qu'il est possible d'avoir quelque chose après (avec les modificateurs appropriés):

say "a\nb\n" =~ m/$ ./msx; 

imprime "1". Le modificateur /x permet l'utilisation d'espaces blancs imbriqués afin que nous puissions séparer le $ du . pour éviter qu'il soit interprété comme une variable.

Questions connexes