(?! ...)
Operador de ``trailing'' o ``mirar-adelante'' negativo.
Por ejemplo /foo(?!bar)/
contiene a cualquier ocurrencia de foo
que no vaya seguida de bar
.
Aparentemente el operador ``mirar-adelante'' negativo es parecido a usar el operador ``mirar-adelante'' positivo
con la negación de una clase. Sin embargo existen al menos dos diferencias:
\d+(?!\.)
casa con $a = '452'
, mientras que \d+(?=[^.])
lo hace, pero porque
452
es 45
seguido de un carácter que no es el punto:
> cat lookaheadneg.pl #!/usr/bin/perl $a = "452"; if ($a =~ m{\d+(?=[^.])}i) { print "$a casa clase negada. \$& = $&\n"; } else { print "$a no casa\n"; } if ($a =~ m{\d+(?!\.)}i) { print "$a casa predicción negativa. \$& = $&\n"; } else { print "$b no casa\n"; } nereida:~/perl/src> lookaheadneg.pl 452 casa clase negada. $& = 45 452 casa predicción negativa. $& = 452
Otros dos ejemplos:
^(?![A-Z]*$)[a-zA-Z]*$
casa con líneas formadas por secuencias de
letras tales que no todas son mayúsculas.
^(?=.*?esto)(?=.*?eso)
casan con cualquier línea en la que aparezcan
esto
y eso
. Ejemplo:
> cat estoyeso.pl #!/usr/bin/perl my $a = shift; if ($a =~ m{^(?=.*?esto)(?=.*?eso)}i) { print "$a matches.\n"; } else { print "$a does not match\n"; } >estoyeso.pl 'hola eso y esto' hola eso y esto matches. > estoyeso.pl 'hola esto y eso' hola esto y eso matches. > estoyeso.pl 'hola aquello y eso' hola aquello y eso does not match > estoyeso.pl 'hola esto y aquello' hola esto y aquello does not matchEl ejemplo muestra que la interpretación es que cada operador mirar-adelante se interpreta siempre a partir de la posición actual de búsqueda. La expresión regular anterior es básicamente equivalente a
(/esto/ && /eso/)
.
(?!000)(\d\d\d)
casa con cualquier cadena de tres dígitos que no
sea la cadena 000
.
Nótese que el ``mirar-adelante'' negativo
es diferente del ``mirar-atrás''. No puede usar este operador
para ``mirar-atrás'': (?!foo)bar/
no casa con una aparición
de bar
que no ha sido precedida de foo
. Lo que
dice (?!foo)
es que los tres caracteres que siguen no puede ser foo
.
Así, foo
no pertenece a (?!foo)bar/
, pero
foobar
pertenece a (?!foo)bar/
porque bar
es una cadena
cuyos tres siguientes caracteres son bar
y no son foo
.
> cat foobar.pl #!/usr/bin/perl my $a = shift; if ($a =~ m{(?!foo)bar}i) { print "$a casa la primera. \$& = $&\n"; } else { print "$a no casa la primera\n"; } if ($a =~ m{(?!foo)...bar}i) { print "$a casa la segunda. \$& = $&\n"; } else { print "$a no casa la segunda\n"; } > foobar.pl foo foo no casa la primera foo no casa la segunda > foobar.pl foobar foobar casa la primera. $& = bar foobar no casa la segundaSi quisieramos conseguir algo parecido tendríamos que escribir algo asi como
/(?!foo)...bar/
que casa con una cadena de tres caracteres que no sea foo
seguida de bar.
En realidad, es mucho mas fácil escribir:
if (/bar/ and $` !~ /foo$/)
Veamos otro ejemplo:
1 #!/usr/bin/perl -w 2 $s = "foobar"; 3 if ($s =~ /(?!foo)bar/) { 4 print "$s matches (?!foo)bar\n"; 5 } 6 if ($s !~ /(?!foo)...bar/) { 7 print "$s does not match (?!foo)...bar\n"; 8 } 9 if ($s =~ /bar/ and $` !~ /foo$/) { 10 print "$s matches /bar/ and \$` !~ /foo\$/\n"; 11 } 12 else { 13 print "$s does not match /bar/ and \$` !~ /foo\$/\n"; 14 }Los resultados de la ejecución de este ejemplo son:
> lookbehind.pl foobar matches (?!foo)bar foobar does not match (?!foo)...bar foobar does not match /bar/ and $` !~ /foo$/
Casiano Rodríguez León