Página 1 de 1

Cómo detectar poblaciones en un texto

NotaPublicado: 2011-08-15 06:31 @313
por crawler
Hola a todos, soy nuevo en el foro y necesito un poco de ayuda.

Estoy tratando de realizar un programa que sepa reconocer las poblaciones de Cataluña en un texto cualquiera.

Tengo guardado como claves de un hash los nombre de las poblaciones y como valor un índice (1..947), para el tratamiento de poblaciones formadas por una sola palabra (ej. Reus, Girona, Sabadell), divido el texto por espacios y compruebo si existe en el hash.

Pero el problema lo tengo para reconocer las poblaciones formadas con más de una palabra, como por ejemplo: La Bisbal d'Empordà, El Vendrell etc...

Disculpad sino me he explicado muy bien y agradeceré cualquier ayuda o sugerencia.

Re: Cómo detectar poblaciones en un texto

NotaPublicado: 2011-08-15 07:19 @346
por explorer
Bienvenido a los foros de Perl en español, crawler.

Aquí hay varios problemas...

¿Qué método usas para realizar la búsqueda?

No nos lo dices, pero podemos hacer algunas suposiciones.

Para saber si un texto está dentro de otro, se suele usar (normalmente):
  • el operador lógico 'eq'
  • la función index() (o la rindex())
  • una expresión regular

Nos comentas que estás dividiendo el texto por los espacios, así que sospecho que estás usando el primer método, el del 'eq'. El problema está en que hay poblaciones con más de una palabra.

Lo podrías resolver complicando un poco más la estructura de datos, buscando por todas las palabras que componen cada población, ampliando el hash, y por cada población, además, saber cuántas palabras lo forman. Pero es que además, deberías llevar el control de si las palabras encontradas están juntas y en el orden adecuado. Desde luego, sería muy complicado, pero con esta solución podrías localizar poblaciones que están escritas "al revés", como por ejemplo, Bisbal d'Empordà, La (solo cambia una palabra de sitio, para dar más importancia a Bisbal).

Otra solución. Con index() puedes buscar si un texto está dentro de otro, y te devuelve la posición (empezando en 0) en donde se encuentre.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #! /usr/bin/perl
  2. use common::sense;              # Hay que tener sentido común
  3. #use Modern::Perl;              # Somos modernos
  4. #use autodie;                   # es mejor morir que regresar con deshonor (proverbio Klingon)
  5. #use utf8;                      # este programa está escrito en utf8
  6. use open qw(:utf8 :std);        # la salida y la entrada estándar serán en utf8
  7.  
  8. my $texto = "
  9. Reus es una población de Cataluña, de Reus
  10. La Bisbal d'Empordà jhf sdkjfh sakdlfh sdkfh skhf sdkf dkjfh
  11. sdlkjfh sdlkjfh slkjfh sdklfjh sklfjh sdklfjh sdkjfh sdkfh
  12. ksdf kdjfh sdkfh sf El Vendrell fjdh fskdjfh skdjfh ksdjfh
  13. Gironaslkfj lkjf lskjf lsdkjf sdljf La Bisbal d'Empordà
  14. sldfj ljflsdkjf ";
  15.  
  16. my @poblaciones = (
  17.     'Reus', 'Girona', 'Sabadell',
  18.     "La Bisbal d'Empordà", 'El Vendrell',
  19. );
  20.  
  21. for my $población (@poblaciones) {
  22.     my $pos = 0;
  23.     while($pos = index($texto, $población, $pos) + 1 ) {
  24.         print "Población $población encontrada en posición $pos\n";
  25.     }
  26. }
  27. __END__
  28. Población Reus encontrada en posición 2
  29. Población Reus encontrada en posición 40
  30. Población Girona encontrada en posición 224
  31. Población La Bisbal d'Empordà encontrada en posición 45
  32. Población La Bisbal d'Empordà encontrada en posición 260
  33. Población El Vendrell encontrada en posición 185
  34.  
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4


Funciona, pero siempre y cuando las poblaciones estén escritas de la misma manera en que las tienes definidas en el array.

Pero no es perfecto. Fíjate que ha encontrado 'Girona', pero está "pegada" a la palabra que le sigue: index() no sabe distinguir entre palabras y espacios. Solo busca cadenas de caracteres. Y en algunos casos no nos servirá.

Otra solución, usando expresiones regulares.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #! /usr/bin/perl
  2. use common::sense;              # Hay que tener sentido común
  3. #use Modern::Perl;              # Somos modernos
  4. #use autodie;                   # es mejor morir que regresar con deshonor (proverbio Klingon)
  5. #use utf8;                      # este programa está escrito en utf8
  6. use open qw(:utf8 :std);        # la salida y la entrada estándar serán en utf8
  7.  
  8. my $texto = "
  9. Reus es una población de Cataluña, de Reus
  10. La Bisbal d'Empordà jhf sdkjfh sakdlfh sdkfh skhf sdkf dkjfh
  11. sdlkjfh sdlkjfh slkjfh sdklfjh sklfjh sdklfjh sdkjfh sdkfh
  12. ksdf kdjfh sdkfh sf El Vendrell fjdh fskdjfh skdjfh ksdjfh
  13. Gironaslkfj lkjf lskjf lsdkjf sdljf La Bisbal d'Empordà
  14. sldfj ljflsdkjf sabadell df slkjf slfj El vendrell
  15. LA BISBAL D'EMPORDÀ Y REUS";
  16.  
  17. my @poblaciones = (
  18.     'Reus', 'Girona', 'Sabadell',
  19.     "La Bisbal d'Empordà", 'El Vendrell',
  20. );
  21.  
  22. for my $población (@poblaciones) {
  23.  
  24.     while ($texto =~ /\b$población\b/gsmi) {
  25.  
  26.         print "Población $población encontrada en posición ", pos($texto), "\n";
  27.     }
  28. }
  29.  
  30. __END__
  31. Población Reus encontrada en posición 5
  32. Población Reus encontrada en posición 43
  33. Población Reus encontrada en posición 356
  34. Población Sabadell encontrada en posición 303
  35. Población La Bisbal d'Empordà encontrada en posición 63
  36. Población La Bisbal d'Empordà encontrada en posición 278
  37. Población La Bisbal d'Empordà encontrada en posición 349
  38. Población El Vendrell encontrada en posición 195
  39. Población El Vendrell encontrada en posición 329
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Fíjate, que además de encontrar todas las posiciones anteriores, podemos:
  • saber cuándo es una palabra separada de las demás (Girona ya no se encuentra, porque en el texto aparece como Gironaslkfj)
  • no importa si está escrito en mayúsculas o no (última línea del $texto) o mezclado (el caso de "El vendrell")

Yo te recomiendo que mires esta opción de usar expresiones regulares (aparte que es muy sencilla: solo buscamos por $población, separada del texto del $texto por \b, que marca los límites de una palabra. Y la buscamos independientemente de si está en mayúsculas o no (/i).

Atento a la codificación de caracteres que estés usando... eso también influye.

Re: Cómo detectar poblaciones en un texto

NotaPublicado: 2011-08-15 10:37 @484
por crawler
Muchas gracias explorer por tu rapidez y tu solución, te explico que antes he sido muy directo.

Estoy realizando una araña que ya es capaz de extraer de los canales culturales de sindicalizacion, el texto del titular, un texto que yo le llamo "información" ( normalmente informa de la fecha, hora y lugar publicados por el autor) y el texto puramente de la noticia.

Bien a partir de estos campos necesito comprobar si alguno de estos contiene la población para más tarde geolocalizar el evento.

Normalmente en la mayoría de noticias, el texto "información" facilita el nombre de la población,

Para realizar la búsqueda, separo el texto del campo "información" por espacios y compruebo si existe como llave del hash que contiene las poblaciones, este criterio solo sirve para encontrar las poblaciones de un palabra y computacionalmente hablando es eficiente.

ej:
@palabras_informacion = split(/\s+/, $text_informacion);

foreach my $i (@palabras_informacion)
{
if( exists ( $municipios{$i}) )
{
$ubicacion = $i;
print "Trobat per clau -> text_info: $ubicacion\n";
last;
}
}



El último criterio es buscar dentro del texto de la noticia.

Como bien dices, con expresiones regulares puedo casi reconocer en el texto si hay una población pero realmente es complejo ya que existen demasiadas ambigüedades y ocurrencias.

De todas formas te agradezco muchísimo tus consejos y tu tiempo, creo que seguiré por el camino de las expresiones regulares.

Re: Cómo detectar poblaciones en un texto

NotaPublicado: 2011-08-17 18:44 @822
por pvaldes
Yo no separaría el texto en palabras, de hecho igual haría justo lo contrario.

Me explico:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
"Caminando por El Vendrell, siguiendo la carretera encontramos el pueblo del Ven-
drell"
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Hay dos problemas aquí.

Pero si quitamos todos los espacios en blanco, los saltos de carro y los guiones y encima pasamos todo a minúsculas.

"caminandoporelvendrell,siguiendolacarreteraencontramoselpueblodelvendrell"

Aparecen ambas citas,

Es una postura extrema desde luego, simplemente para poner de manifiesto que tienes que considerar la posibilidad de que se inserte un guión traicionero y un salto de línea.