• Publicidad

Búsqueda especial

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Búsqueda especial

Notapor jorcaes » 2007-09-14 09:34 @440

Hola a todos, necesito su ayuda en un tipo de búsqueda que a continuación detallo.

Dispongo de un fichero de texto con el siguiente formato:

Código: Seleccionar todo
<s> Introducción </s>

Texto de introducción

<s> Desarrollo </s>

Texto del desarrollo

<s> Conclusión </s>

Texto de la conclusión


Lo que necesito es buscar palabras concretas (de un listado) y ubicarlas en cada una de las secciones <s> Sección </s>, pongamos un ejemplo:

La palabra campeón hay que ubicarla, entonces se empieza a buscar por el texto, si se encuentra en el texto de la sección Desarrollo, pues se debe anotar en su correspondiente sección, mostrando el resultado en una matriz de la siguiente manera:

Imagen

¿Cómo debo realizar la búsqueda? Es decir, ¿qué patrón usaríais para realizar las búsquedas? Sé que debo emplear los tags de sección <s> xxx </s> pero ¿cómo saber en qué sección nos encontramos?

Espero que puedan ayudarme a resolver esta duda que se me ha presentado.

Un saludo y gracias.
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Publicidad

Notapor jorcaes » 2007-09-14 10:56 @497

¿Por qué esto NO me funciona?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
        if ($palabra =~ /^<s>/)
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Quiero buscar las cadenas que tengan este formato:

<s>[espacio o no]texto[espacio o no]textoabuscar</s>
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor kidd » 2007-09-14 17:34 @774

Según lo que comentas, es esto más o menos el camino que yo seguiría:

  1. Abrir el archivo.
  2. Hacer un primer parse del archivo y separar cada seccion en una variable distinta.
  3. Realizar la búsqueda de la palabra en cada sección.

En caso de que tus archivos de texto sean demasiado grandes, entonces se deberá de realizar un diferente camino pues tomará demasiada memoria.

El regexp para realizar la siguiente búsqueda:
Código: Seleccionar todo
<s>[espacio o no]texto[espacio o no]textoabuscar</s>


Sería de la siguiente manera:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
m/^\<s\>\s*\w+\s*(palabra)\<\/s\>$/mi;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Explicada la expresión:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
^          #inicio de línea
\<s\>    #empieza un <s>
\s*        #espacio o no
\w+      #texto
\s*        #espacio o no
(palabra) #otro texto
\<\/s\>  # </s>
$ #fin de línea
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Saludos
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Notapor jorcaes » 2007-09-15 02:32 @147

Hola, muchas gracias por responder, me diseve muchísimo la indicación que me haces, pero sigo sin poder detectar las palabras dentro de una sección concreta. A ver si puedo explicarme un poco mejor.

Tengo un documento de texto de la siguiente forma:

Código: Seleccionar todo
LA FIA HACE PÚBLICOS LOS MOTIVOS DE LA SANCIÓN A McLAREN

<s>1. Introducción</s>

Alonso y De la Rosa recibieron datos confidenciales de Ferrari
EFE. Spa La Federación Internacional del Automóvil (FIA) hizo públicos los motivos por los que sancionó con dureza al equipo McLaren-Mercedes y entre ellos incluye algunos correos electrónicos de Fernando Alonso y Pedro de la Rosa que "muestran inequívocamente" que ambos recibieron, vía (Mike) Coughlan, información confidencial de la escudería Ferrari.

<s>2. Desarrollo</s>
La FIA asegura que tanto Alonso como De la Rosa "sabían que esta información de Ferrari era confidencial" y que fue (Nigel) Stepney, ex ingeniero de Ferrari, quien se la facilitó a Mike Coughlan, ex jefe de diseño de McLaren.

La FIA afirma en sus explicaciones que "el 21 de marzo de 2007, a las 9:57, el señor De la Rosa escribió a Coughlan en los siguientes términos: 'Hola Mike: ¿Sabes cuál es el reparto de pesos de los coches rojos? Sería importante para nosotros saberlo para que podamos probar en el simulador. Gracias de antemano. Pedro. Posdata: Estaré mañana en el simulador'".

<s>Conclusión</s>
La distribución de pesos
Asimismo, la FIA incluye otro correo electrónico de De la Rosa enviado el 25 de marzo de 2007 a las 1:43 a Alonso, en el que le informa de la distribución de pesos que Ferrari iba a usar en sus dos coches en el Gran Premio de Australia, primero de la presente temporada.


Bien, ése es, más o menos, el formato de mis ficheros. Ahora bien, tengo que encontrar todas la apariciones de la palabra ALONSO (2 en Introducción, 1 Desarrollo y 1 Conclusión) y mostrar el resultado en un fichero Excel:

Imagen

El caso es que tengo el siguiente código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#Leemos la lista de palabras keywords que está al final del código
my %keywords;
while ( <DATA> ){
        chomp;
        $keywords{ lc($_) }=1;
}

# get a new workbook
$book = $ex->Workbooks->Add;
# nos ubicamos en la primera hoja sheet
$sheet = $book->Worksheets(1);

$fila = 2;
$columna = 2;

#Para cada fichero...
foreach my $nombre_fichero ( <C:\\Mis_Ficheros\\*.txt> ){
        #Nos leemos todo el fichero y lo dividimos en palabras
        my @palabras;
        {
                my $fichero=do{ local $/; open FH, "<$nombre_fichero"; <FH> };
                @palabras = $fichero =~ /(\b[^\W_\d][\w'-]+\b)/g;
        }
       
        #AQUÍ ES DONDE NO SÉ CÓMO SEGUIR
        #¿QUÉ ESTRUCTURA TIENEN QUE TENER LOS BUCLES?

        #Para todas las palabras del fichero
        my $palabra;
        foreach my $palabra_org ( @palabras ) {
                $palabra = lc($palabra_org);
                if ($palabra =~ /^\<s\>/) {
                        print "He encontrado la palabra: $palabra\n";
                }
        }
}

# save and exit
        $book->SaveAs( 'C:\My_Excel.xls' );
        undef $book;
        undef $ex;

__DATA__
ALONSO
FERRARI
...
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Espero que con esta explicación alguien pueda orientarme sobre qué hacer con la parte donde no sé cómo seguir.

Un saludo y gracias.
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor explorer » 2007-09-15 06:22 @307

Dado el texto anterior, con el siguiente programa

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
        1 #! /usr/bin/perl -wl
        2
        3 use locale;
        4
        5 {
        6     local $/ = '<s>';
        7     open TEXTO,'<kk.txt';
        8     @secciones = <TEXTO>;
        9     close TEXTO;
       10 }
       11
       12 while ( $termino_a_buscar = <DATA> ) {
       13
       14     chomp $termino_a_buscar;
       15
       16     foreach $seccion ( @secciones ) {
       17
       18         next if $seccion !~ m{(\w+)</s>};
       19
       20         $nombre_de_la_seccion = $1;
       21
       22         $numero_de_veces = () = $seccion =~ /$termino_a_buscar/misg;
       23
       24         print "$termino_a_buscar: $nombre_de_la_seccion : $numero_de_veces";
       25
       26     }
       27 }
       28
       29 __DATA__
       30 ALONSO
       31 FERRARI
       32
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

la salida es:
Código: Seleccionar todo
ALONSO: Introducción : 2
ALONSO: Desarrollo : 1
ALONSO: Conclusión : 1
FERRARI: Introducción : 2
FERRARI: Desarrollo : 2
FERRARI: Conclusión : 1

Algunas explicaciones:
  • En la primera línea activamos los avisos (-w) y los finales de línea automáticos (-l) -somos muy vagos-.
  • De la línea 6 a la 9 leemos el fichero de texto. Usamos un par de detalles fuera de lo común.
  • Primero, localizamos la variable especial $/ en un contexto propio (el marcado por las llaves de las líneas 5 y 10), de tal forma que solo tendrá el valor que le hemos indicado en la línea 6 durante ese contexto, y que recuperará su valor original al final del contexto. Esto es necesario porque luego queremos leer desde la sección DATA de forma normal -una línea de texto en cada lectura-.
  • Y segundo: la misma variable $/ es la define cómo son los separadores o delimitadores de registro en el momento de leer de ficheros externos. Si lo definimos como '<s>' le estamos diciendo que cada vez que le pidamos un 'registro' al fichero -en una operación de lectura- nos tiene que devolver todo lo que se encuentre rodeado por esos caracteres. En nuestro ejemplo, la sección número 2 tiene este aspecto:
    Código: Seleccionar todo
    2. Desarrollo</s>
    La FIA asegura que tanto Alonso como De la Rosa "sabían que esta información
    de Ferrari era confidencial" y que fue (Nigel) Stepney, ex ingeniero de
    Ferrari, quien se la facilitó a Mike Coughlan, ex jefe de diseño de McLaren.

    La FIA afirma en sus explicaciones que "el 21 de marzo de 2007, a las 9:57,
    el señor De la Rosa escribió a Coughlan en los siguientes términos: 'Hola
    Mike: ¿Sabes cuál es el reparto de pesos de los coches rojos? Sería
    importante para nosotros saberlo para que podamos probar en el simulador.
    Gracias de antemano. Pedro. Posdata: Estaré mañana en el simulador'".

    <s>
    Como ves, de una manera muy sencilla leemos cada sección de forma separada.
  • En la línea 8 leemos todas las secciones de golpe, cada una en un elemento de un array
  • Luego está el bucle por todos los $terminos_a_buscar
  • Y por cada $termino_a_buscar, miramos en cada $seccion para todas las @secciones
  • En la línea 18 hay algo especial: una expresión regular que desechará aquellas secciones que no nos interesan -el encabezado con el titular-, y, al mismo tiempo y gracias a los paréntesis de captura, sabremos el nombre de la sección. Aquí hay que destacar un detalle: como las secciones tienen caracteres 'especiales' -los acentos- necesitamos que \w+ también los capture. Por eso, en la línea 3 le decimos a Perl que en las operaciones de cadenas de caracteres y expresiones regulares use la codificación local de caracteres -de nuestro sistema-. El $nombre_de_la_seccion lo guardaremos en la línea siguiente.
  • Y la línea 22. Aquí hay mucha tela que cortar. Lo que hace es: busca en la $seccion el $termino_a_buscar, sin importar las mayúsculas y minúsculas (/i), en un texto que tiene varias líneas (/ms) y todas las veces posibles (/g). Esta expresión regular la ejecutamos en contexto lista, con la ayuda de un par de paréntesis. Perl obtiene todos los términos encontrados y los mete como una lista de valores dentro de ese par de paréntesis... con lo que entonces... se pierden... -no hay variables esperando a esos valores-, PERO lo que nos importa solamente es CUÁNTOS han sido, por eso, a continuación, la lista de valores del par de paréntesis es ejecutado en contexto escalar -con la presencia de la variable escalar primera de la línea- y es justo lo que queremos: el $numero_de_veces que aparece el término en la sección.
    Esta línea hace 'lo mismo' que estas otras:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using perl Syntax Highlighting
            $numero_de_veces = 0;
            while ( $seccion =~ /$termino_a_buscar/misg ) {
                $numero_de_veces++;
            }
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
    Sin duda, esta es la línea que marca la diferencia entre Perl y todo lo demás.
  • Solo resta pintar lo encontrado.
Decir que todo esto es posible porque el texto de partida tiene un formato regular (secciones con separadores/marcadores claros y colocados de forma regular).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14482
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-09-21 16:33 @731

Guau, ¡lo tuyo es increíble, explorer!

Me ha ayudado muchísimo, en serio, tan sólo me ha faltado plasmar los resultados en sus correspondientes celdas en un Excel.

Ahora bien, tengo un par de dudas ahora mismo:

1. ¿Cómo puedo hacer todas las operaciones del programa para cada uno de los ficheros de texto contenidos en un mismo directorio?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach my $fichero ( <C:\\DIRECTORIO\\*.txt> ){

# Esta parte no sé cómo debería ir... por lo de la variable local y tal
{
        local $/ = '<s>';
        open TEXTO, '<PRUEBA2.txt';
        @secciones = <TEXTO>;
        close TEXTO;
}

#Resto del programa
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


No me interesa almacenar los resultados por cada fichero, por lo que estoy empleando el operador += para que me haga una suma agregada por cada aparición($numero_de_veces) de $termino_a_buscar en $nombre_de_la_seccion.


2. Ahora que tengo la división por secciones, también tengo que realizar las mismas operaciones, pero esta vez sin tener en cuenta el operador de división de secciones (<s> </s>), es decir, ahora necesito dividir el texto en 5 secciones, y la forma de obtener dichas secciones es el Número_total_de_palabras dividido entre 5. Así la primera sección serán 1/5 del total de las palabras del texto. ¿Existe alguna forma directa de realizar esta división?

¡Muchas gracias por todo!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor explorer » 2007-09-23 17:01 @751

1. El contexto ({}) garantiza que $/ no afectará al resto de ficheros abiertos del programa.

2. No, no hay una forma fácil. Tendrás que leer todo el texto, sacar todas las palabras y meterlas en un array. Luego, la longitud del array nos dirá el $numero_total_de_palabras y de ahí podremos dividirlo en 5 partes.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14482
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-10-05 15:46 @698

Hola, después de cierto tiempo ya vuelvo a estar por aquí. Como siempre me gustaría agradecer la colaboración de Explorer por toda la ayuda que me está ofreciendo, ahora bien, vamos a pasar al trabajo...

Tengo que adaptar el anterior código para que las secciones se ajusten a un quinto del total de palabras del texto. Tengo el $numero_total_de_palabras, pero no sé cómo generar la división de las secciones.

Lo que me interesa conocer es el número de apariciones de cada una de las keyword de la sección DATA en cada una de las secciones, las cuales serán siempre cinco.

Tengo el siguiente código:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach my $fichero ( <C:\\MI_DIRECTORIO\\*.txt> ){

        my @palabras;
        {
                my $fich=do{ local $/; open FH, "<$fichero"; <FH> };
                @palabras = $fich =~ /(\b[^\W_\d][\w'-]+\b)/g;
        }
        $numero_total_de_palabras = $#palabras;

        #esta parte se utilizaba para dividir el texto en las secciones delimitadas por el separador <s>

        {
               #supongo que AQUÍ se deberá hacer la división entre las cinco secciones y almacenarlas en $secciones[0] - $secciones[4]
                local $/ = '<s>';
                open TEXTO, $fichero;
                @secciones = <TEXTO>;
                close TEXTO;
        }

        $data_pos = tell DATA;
        while ( $termino_a_buscar = <DATA> ) {
                       
                chomp $termino_a_buscar;
                                               
                foreach $seccion (@secciones){
                               
                        #si es la primera sección, se almacenará en la primera columna de un Excel, si es la segunda sección, en la segunda columna y así hasta la quinta sección/columna
                               
                        $numero_de_veces = () = $seccion =~ /$termino_a_buscar/misg;

                        #código donde almacenan los resultados en el excel

                }
        }
        seek DATA, $data_pos ,0;
}

_DATA_
keyword1
keyword2
keyword3
...
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Espero que me puedan resolver esta duda, ya que no consigo avanzar en este desarrollo, y el resto de script ya los tengo funcionando al 100%. ¡¡¡Muchísimas gracias a todos!!!
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Notapor explorer » 2007-10-05 19:19 @846

jorcaes escribiste:Tengo que adaptar el anterior código para que las secciones se ajusten a un quinto del total de palabras del texto. Tengo el $numero_total_de_palabras, pero no sé cómo generar la división de las secciones.
Si lo entiendo... que por un lado necesitamos saber el $numero_total_de_palabras, y, como hay cinco secciones, hacer que cada sección tenga como máximo un quinto de esas palabras. No hay problema con las secciones que tengan más de un quinto del total, pero, ¿qué hacemos con las secciones que tengan menos palabras?.

Un ejemplo. En un texto hay 500 palabras, que se reparten en las 5 secciones así: 100, 150, 50, 180 y 20. ¿Qué hacemos?

Si, suponemos, que no nos importan las secciones que tienen menos de 100 palabras, entonces las secciones quedan así: 100, 100, 50, 100 y 20. ¿Es correcto?

jorcaes escribiste:Tengo el siguiente código:
$#palabras; no es el número de palabras. Es el número del índice del último valor del array @palabras. Si @palabras tiene 20 elementos, $#palabras vale 19.

Es mejor que escribas la línea así: $numero_total_de_palabras = @palabras; . Un array en contexto escalar devuelve el número de sus elementos.

jorcaes escribiste:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
               #supongo que AQUÍ se deberá hacer la división entre las cinco secciones y almacenarlas en $secciones[0] - $secciones[4]
                local $/ = '<s>';
                open TEXTO, $fichero;
                @secciones = <TEXTO>;
                close TEXTO;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

En este momento tienes las secciones leídas. Debes recorrerlas. En cada una, sacar las palabras y meterlas en un array. Y luego limitar a un máximo de un quinto del total.

Todo este trabajo de leer el fichero, que realmente lo haces dos veces, se podría hacer solo una: leer las secciones y sacando sus palabras, guardarlas en una estructura de un array de arrays:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@secciones = (
    [           # sección 0
        "palabra1",
        "palabra2",
        "palabra3",
        # ...
        "palabraN",
    ],
    [           # sección 1
        "palabra1",
        "palabra2",
        "palabra3",
        # ...
        "palabraN",
    ],
                # resto de secciones ...
);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Así, solo es necesario leer el $fichero una vez (todo a memoria, en esa estructura). Es fácil saber el número total de palabras (sumando las palabras de todas las secciones). Ajustar a un quinto cada conjunto de palabras se puede hacer con splice(). Recorrer y probar la búsqueda de keywords es hacer un doble bucle (por sección y por cada palabra de sección). La expresión regular cambia y en vez de decirnos el $numero_de_veces, nos vale si coincide o no con la palabra buscada. En cada coincidencia, sumamos uno en otra 'matriz' de datos (puede ser escribir el resultado directamente en el Excel o en otro array de arrays).

jorcaes escribiste:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
seek DATA, $data_pos ,0;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


En lugar de leer de DATA constantemente, es mucho mejor leer las keywords una sola vez, al principio del programa, y meterlas en un array, por ejemplo, @keywords.

No sé si te he liado más... solo he intentado simplificar la solución al máximo. Además, como estamos con Perl, son perfectamente válidas cualquiera de las otras 9 posibles soluciones...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14482
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor jorcaes » 2007-10-06 01:43 @113

Muchísimas gracias por la explicación, pero creo que no me he explicado demasiado bien.

Si tenemos un texto con 1000 palabras, cada una de las secciones tendrán 200 palabras, TODAS las secciones serán de IGUAL tamaño de palabras.

La otra parte que no entiendo es la de meter las palabras en cada una de las secciones:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@secciones = (
    [           # sección 0
        "palabra1",
        "palabra2",
        "palabra3",
        # ...
        "palabraN",
    ],
    [           # sección 1
        "palabra1",
        "palabra2",
        "palabra3",
        # ...
        "palabraN",
    ],
                # resto de secciones ...
);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Muchas gracias por la diligencia Explorer, como siempre :)

Saludos.
jorcaes
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2006-07-12 02:35 @149

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados