(?! ...)
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 match
El 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 segunda
Si 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
