• Publicidad

Extraer cadena de texto no específico

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

Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-20 18:34 @815

Saludos,

Soy bastante nuevo en Perl, de hecho no sé nada. El problema que tengo es que necesito sacar de un archivo de texto varias cadenas de texto.

El archivo es algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Jun 19 07:17:15 VERBOSE [3548] chan_sip.c: -- Registered SIP '50206' at 10.75.16.25 port 43932
Jun 19 07:17:15 NOTICE  [3548] chan_sip.c: Peer '50206' is now Reachable. (30ms / 2000ms)
Jun 19 07:17:15 VERBOSE [3548] netsock.c: == Using SIP RTP TOS bits 184
Jun 19 07:17:15 VERBOSE [3548] netsock.c: == Using SIP RTP CoS mark 5
Jun 19 07:17:15 VERBOSE [5369] pbx.c: -- Executing [950206@from-internal:1] Macro("SIP/50206-0000002b","user-callerid,")
Jun 19 07:17:15 VERBOSE [5369] pbx.c: -- Executing [s@macro-user-callerid:1] Set("SIP/50206-0000002b", "AMPUSER=50206")
Jun 19 07:17:15 VERBOSE [5369] pbx.c: -- Executing [s@macro-user-callerid:2] GotoIf("SIP/50206-0000002b", "0?report")
Jun 19 07:17:15 VERBOSE [5369] pbx.c: -- Executing [s@macro-user-callerid:3] ExecIf("SIP/50206-0000002b",CALLERIDNUM=50206
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4



El archivo tiene muchas líneas. Lo que necesito extraer hacia otro archivo de texto son las siguientes cadenas de texto: 50206 y 10.75.16.25

En el archivo original puede existir por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Jun 19 07:17:15 VERBOSE [3548] chan_sip.c: -- Registered SIP '50207' at 10.75.16.210 port 43932
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

y en este caso entonces tendría que sacar:
50207 y 10.75.16.210

y junto con la primera línea, el archivo .txt resultante quedaría así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
50206 10.75.16.25
50207 10.75.16.210
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


y así sucesivamente por cada vez que exista una línea que contenga el texto: SIP 'XXXXX' y at XX.XX.XX.XX (las demás líneas no me interesan por ahora).

En español debería ser algo así:

Si en la línea existe el texto SIP y el texto at entonces seleccione lo que está justo después de SIP (sin las comillas) y lo que está después de at (sin importar la longitud) y guárdalo en otro archivo de texto de tal manera que quede así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
50206 10.75.16.25
50207 10.75.16.210
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


De lo contrario, null.

Es de anotar que lo que está después de at podría ser, por ejemplo, 10.75.16.12 y también 10.120.45.160.

Gracias de antemano por la ayuda.
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Publicidad

Re: Extraer cadena de texto no específico

Notapor explorer » 2012-06-20 19:14 @843

Bienvenido a los foros de Perl en Español, juancs011.

Perl es un lenguaje muy bueno para tareas como la que muestras.

Por ejemplo, el siguiente programa resuelve el problema, sin más que con poner los nombres correctos de los archivos que quieres leer/escribir:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;             # programación estricta de Perl
  3. use warnings;           # activar las advertencias
  4. use diagnostics;        # advertencias realmente ruidosas
  5.  
  6. open my $LOG, q[<], 'code_31601.txt'
  7.      or die "ERROR: No pude abrir el registro de actividad: $!\n";
  8.  
  9. open my $OUT, q[>], 'kk.txt'
  10.      or die "ERROR: No puedo escribir el resultado: $!\n";
  11.  
  12. while (readline $LOG) {
  13.     if (/ SIP '(.+?)' at (\S+)/) {      # Si en la línea existe el texto 'SIP' y el texto 'at'
  14.         my $sip = $1;                   # entonces seleccione lo que está justo después de 'SIP' (sin las comillas)
  15.         my $ip  = $2;                   # y lo que está después de 'at' (sin importar la longitud)
  16.  
  17.         print $OUT "$sip $ip\n";        # y guárdalo en otro archivo de texto
  18.     }
  19. }
  20.  
  21. close $LOG;
  22. close $OUT;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Como es normal en muchos programas de Perl, hacemos uso de las Expresiones regulares para "cazar" la información que queremos.

La expresión regular quiere decir:
  • busca por el literal " SIP '" (espacios en blanco y comilla simple, incluidos)
  • captura todo lo que encuentres ((.+?)'), hasta la primera comilla simple que encuentres
  • lo capturado lo metes en $1 (por ser el primer par de paréntesis)
  • luego busca por ( at ),
  • y guarda todo lo que sigue, que no sea espacio en blanco (\S+)
  • y lo capturado lo metes en $2 (por ser el segundo...)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-21 09:35 @441

Simplemente excelente. Gracias.
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Re: Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-21 15:08 @672

Otra pregunta:

¿Y si quisiera también extraer la fecha que está al comienzo de la línea (Jun 19 07:17:15) y justo antes de la palabra VERBOSE?

Jun 19 07:17:15 VERBOSE

¿Y qué tal si esta cadena no estuviese al comienzo de la línea? Entonces no llevaría el símbolo ^, pregunto.

O, si no estuviese antes de la palabra VERBOSE, es decir, quisiera extraer la fecha (Jun 19 07:17:15) que está en la misma línea que contiene las palabras 'SIP' y 'at'.

PD. Ya he estado leyendo manuales pero no he encontrado estas respuestas.

Gracias nuevamente.
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Re: Extraer cadena de texto no específico

Notapor explorer » 2012-06-21 18:29 @812

juancs011 escribiste:Ya he estado leyendo manuales pero no he encontrado estas respuestas.
¿Qué manuales has estado leyendo?
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-22 08:29 @395

Hola, buenos días. Descargué un manual de una página http://www.lawebdelprogramador.com. Allí explican la sintaxis para extraer diferentes tipos de texto, pero tengo unas dudas que no he encontrado:

En el ejemplo que tu me enviaste al principio se extrae la cadena que está inmediatamente después de las palabras 'SIP' y 'at', pero ¿cómo podría extraer esas cadenas sin saber la ubicación dentro del texto completo, sin tener como referencia otras palabras (SIP y at)?

Es sobre esto que he estado leyendo. La pregunta que te hacía en el comentario anterior es para saber cómo extraer una palabra que se encuentra "antes" de otra. En el ejemplo que me diste se está extrayendo lo que está "después" de SIP y de at, ahora bien, ¿cómo hago eso pero si la cadena que quiero extraer está "antes" de la palabra de referencia (SIP).

Muchas gracias.
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Re: Extraer cadena de texto no específico

Notapor explorer » 2012-06-22 11:30 @521

Para extraer algo, debe darse una de estas condiciones:
  • sabemos la posición exacta ("Está a 20 caracteres del principio de la línea")
  • sabemos que está con respecto a otra cosa -el ancla- ("Es la siguiente palabra a "SIP")
  • sabemos que cumple una regla genérica ("extraer la segunda dirección IP de la línea")
  • sabemos el aspecto que tiene, y que además, es única en ese texto ("buscar la dirección IP que está en la línea")

En este caso, quieres extraer lo que está antes de "SIP". Si suponemos que "eso" es una palabra (algo diferente del espacio en blanco), entonces el patrón a usar será
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
/(\S+) SIP/
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Observa que estamos capturando cualquier cosa -que no sea espacio en blanco- que está antes de un espacio en blanco y de la palabra "SIP".
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-25 14:23 @641

Hola, esto no es tan fácil como parece.

En el texto del que estoy extrayendo las cadenas de texto tengo lo siguiente (en la misma línea):

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Registered SIP '20606' at 10.72.20.35 port '37932' [Jun 22 05:00:01] VERBOSE[3559]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


(de esto quiero extraer 20606, 10.72.20.35, 37932, Jun 22 05:00:01)

Antes y después de eso hay otras cosas pero no me interesan.

El ejemplo que tu me enviaste extrae correctamente las cadenas de texto "20606" y "10.72.20.35".

Es esto: if (/ SIP '(.+?)' at (\S+) /) y cada paréntesis lo guardo en una variable $1 y $2 las cuales imprimo en el archivo de salida con: print $OUT "$sip,$ip \n";


Ahora quiero extraer también la cadena '37932'. Para eso estoy agregando la misma sección que me extrae el SIP.

Queda algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if (/ SIP '(.+?)' at (\S+) port '(.+?)' /)
  2.        {
  3.  
  4.        my $sip = $1;
  5.  
  6.        my $ip  = $2;
  7.  
  8.        my $port = $3;
  9.  
  10.        print $OUT "$sip,$ip,$port \n";
  11.  
  12.        }
  13.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Yo asumo que "port '(.+?)'" me va a extraer lo que está después de "port" tal y como lo extrae cuando está después de "SIP" ya que es el mismo tipo de texto (números entre comillas simples). Sin embargo, no hace nada: crea el archivo de salida pero sin nada dentro, ni siquiera extrae lo que originalmente extraía bien (SIP y IP).

Entonces, ¿qué estoy haciendo mal? ¿Qué falta?

Por otra parte, ¿cómo podría extraer la cadena "[Jun 22 05:00:01]" sin corchetes?

Y finalmente, ¿dónde puedo conseguir buen material para aprender a hacer esta clase de extracciones de texto?

Lo que necesito aprender a hacer es, por ejemplo, extraer todo lo que tenga un formato específico. Por ejemplo:

XXX.XXX.XXX.XXX (X es un número entero) o un teléfono XXX-XX-XX

Ha sido un poco frustrante porque he aplicado algunas cosas que he leído pero nada ha funcionado.

Gracias.
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Re: Extraer cadena de texto no específico

Notapor explorer » 2012-06-25 18:35 @816

Pues a mí me funciona:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2.  
  3. my $texto = q(Registered SIP '20606' at 10.72.20.35 port '37932' [Jun 22 05:00:01] VERBOSE[3559]);
  4.  
  5. if ($texto =~ / SIP '(.+?)' at (\S+) port '(.+?)' /) {
  6.     print "[$1][$2][$3]\n";                           # [20606][10.72.20.35][37932]
  7. }
  8.  
  9. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Lo importante es saber *todos los casos posibles* que queremos identificar. Y construir un patrón o varios patrones para reconocerlos.

Para extraer el texto sin los corchetes, habría que escaparlos, antes: \[(.+?)\].

Para aprender expresiones regulares, tienes que empezar por la introducción que hay en Wikipedia. Allí también hay enlaces externos. Uno lleva a uno de nuestros manuales breves (sección tutoriales, arriba). La versión inglesa de la página tiene alguna cosilla más. Por internet tienes más manuales, pero son de calidad muy voluble. O dan información anticuada.

En Perl (en tu propio ordenador), tienes los siguientes documentos:
  • perlre - Expresiones regulares en Perl
  • perlrecharclass - Explicación de las clases de caracteres
  • perlreref - Referencia rápida de las expresiones regulares
  • perlreapi - Descripción de la API para interconectar complementos con el motor de exp. reg.
  • perlreguts - Descripción del funcionamiento del motor de exp. reg. de Perl
  • perlrequick - Iniciación rápida a las exp. reg. en Perl
  • perlrebackslash - Secuencias de escapado con barras diagonales inversas en exp. reg. en Perl
  • perlretut - Manual de expresiones regulares en Perl
Algunos de ellos ya están traducidos.

Es normal que sientas frustración: la definición de los patrones es otro lenguaje, casi independiente del propio Perl. Así que la frustración viene de tener que aprender un lenguaje nuevo. Pero aprenderlo, aunque sea un poco, tiene unos beneficios enormes.

Para extraer cosas como XXX.XXX.XXX.XXX, se puede hacer de varias formas. Una de ellas es la comentada antes: si sé la posición en la que se encuentra (con respecto al ancla), y sé que se compone de cosas que no son espacio en blanco, rodeado de un par de espacios en blanco, pues eso es lo que pongo: /at (\S+) /.

Ahora bien, también puedo decir que lo que busco es un conjunto de cuatro números separados por puntos. Entonces otro patrón podría ser:

/(\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3})/

Ahí estoy diciendo que quiero capturar (()) algo consistente en un grupo de uno a tres dígitos, seguidos por un punto, seguidos por grupo de uno a tres dígitos, seguidos por un punto, etc...

Lo mismo para el teléfono: /(\d{3}-\d{2}-\d{2})/, solo que esta vez indicamos el número exacto de dígitos que esperamos.

Si tienes código que no funciona, intenta reducirlo a unas pocas líneas que formen un programa completo (como hago yo), y nos lo mandas aquí. Así podremos ver dónde está el fallo. Y si pones un ejemplo de la entrada (como también he puesto yo), pues más ayuda será.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Extraer cadena de texto no específico

Notapor juancs011 » 2012-06-26 11:14 @510

Hola, envío adjunto 3 archivos. Te explico:

- prueba.pl fue el que tu me enviaste y funciona perfecto, genera un archivo con las cadenas extraídas del archivo full.txt

- full.txt es un log desde el cual quiero extraer ciertos datos. Hasta ahora sacaste la IP y el número SIP.

- prueba2.pl es el mismo prueba.pl pero yo le agregué la instrucción para extraer lo que está después de la palabra 'port'.

En el archivo full.txt se encuentran las palabras 'SIP', 'at' y 'port' en la misma línea y las palabras que están después de 'SIP' y de 'port' tienen las mismas características (5 números) pero 'SIP' tiene comillas y 'port' no las tiene. Yo lo que hice fue colocar la misma instrucción que me extrae el número 'SIP' para que me extraiga el 'port' pero no funciona, me crea el archivo2.txt pero vacío.

Yo utilizo Notepad como editor y para ejecutar el archivo .pl hago doble clic sobre el archivo y allí mismo se crea el nuevo archivo .txt. Traté de instalar algo que se llama Strawberry pero por políticas de seguridad de la empresa no lo logré instalar bien.

Yo quisiera entender finalmente cómo utilizar esos códigos para extraer cadenas de texto. Lo que tu me explicas brevemente se entiende bien, igualmente el archivo que me enviaste, pero al buscar por Internet y tratar de aplicar cambios a lo que me enviaste no logro hacer que funcione.

Gracias nuevamente por tu colaboración.
Adjuntos
prueba2.pl
Este archivo es igual al prueba.pl pero le agregue extraer lo que esta despues de "port"
(1.05 KiB) 56 veces
prueba.pl
Al ejecutar este archivo, extrae lo que esta entre comillas despues de SIP (sin comillas) y lo que esta despues de at
(1.13 KiB) 46 veces
full.txt
Desde este archivo es de donde voy a extraer las cadenas de texto.
(208.13 KiB) 52 veces
juancs011
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2012-06-20 17:45 @781

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: Google [Bot] y 4 invitados

cron