El carácter '^' tiene dos significados según donde se use. O puede indicar un anclaje a principio de la cadena, o si está dentro de una clase de caracteres
y es el primer carácter de la clase, negar el significado de la clase de caracteres.
Pero es que tu caso no es ninguno de estos dos casos. Lo que quieres es negar la presencia de unas cadenas delante de un patrón.
En teoría, cuando queremos que un patrón
no no sea precedido por una cadena, solemos usar el patrón (?<!patrón) delante de él. Debería ser:
(?<!hace|durante|por) \d{1,3} años?Pero... no funciona. Más bien, saldrá un error, indicando que el patrón que hay que indicar antes debe ser de longitud
fija, y no es así: son tres cadenas, cada uno de una longitud distinta. Y además, en forma de alternativas. No funciona porque debería ser una sola cadena fija.
La solución (la que he encontrado): dividir el problema en dos: primero buscamos el patrón general, y luego comprobamos que la palabra que precede al número no sea una de las prohibidas.
Esta es una forma de verlo:
Using perl Syntax Highlighting
#!/usr/bin/perl
use Modern::Perl; # somos modernos
use utf8; # este programa está escrito en utf8
use autodie; # es mejor morir que regresar con deshonor (proverbio Klingon)
use open ':utf8'; # la codificación de los ficheros es en utf8
use open ':std'; # también en STDIN y STDOUT
my @pruebas = (
'Argumentario 77 years',
'Tiene 231 años',
'Posee 1 año',
'Dame 2 AÑOS',
'largo 2311 años',
'hace 123 años',
'durante 999 años',
'por 2 años',
'estuvo 29 años',
'reclamó 7 años',
'permaneció 4 años',
'PruebaáéíoúñÑdepalabralarga 8 años',
);
for my $texto (@pruebas) {
print "[$texto]:";
# if (utf8::is_utf8($texto)) {
# print "[sí]:";
# }
# else {
# print "[no]:";
# }
if ($texto =~ m{\b(?<palabra>[[:word:]]+)\s+(?<edad>\d{1,3})\s+años?}i) {
if (lc($+{palabra}) ~~ [qw[hace durante por]]) {
say "ERROR1";
}
else {
say "[$+{palabra}][$+{edad}]";
}
}
else {
say "ERROR2";
}
}
__END__
[Argumentario 77 years]:ERROR2
[Tiene 231 años]:[Tiene][231]
[Posee 1 año]:[Posee][1]
[Dame 2 AÑOS]:[Dame][2]
[largo 2311 años]:ERROR2
[hace 123 años]:ERROR1
[durante 999 años]:ERROR1
[por 2 años]:ERROR1
[estuvo 29 años]:[estuvo][29]
[reclamó 7 años]:[reclamó][7]
[permaneció 4 años]:[permaneció][4]
[PruebaáéíoúñÑdepalabralarga 8 años]:[PruebaáéíoúñÑdepalabralarga][8]
Coloreado en 0.003 segundos, usando
GeSHi 1.0.8.4
Y vemos que funciona: las líneas marcadas con ERROR1 son las que contiene las palabras malditas; las que tienen ERROR2, no siguen el formato buscado; el resto sí que son cadenas correctas a lo que buscamos.