• Publicidad

Recorrido de cadenas y separación de campos

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

Notapor explorer » 2006-09-27 05:24 @267

Si no te devuelve nada, es que no hay nada en la base de datos que concuerde con la instrucción SQL que has puesto...

¿Qué es trama{UID}? ¿No será $trama{UID}?
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

Publicidad

Notapor Josmanue » 2006-09-27 07:28 @352

No hombre hasta ahí llego. En la base de datos está el campo, además al introducir la cadena meto deliberadamente 'UIDSP103' cuyo campo servicio =3 para así probar la insercion en la tabla pero no me devuelve el servicio y por tanto no inserta. Además tengo lo mismo en otro programa (que he echo de prueba) y estando exacatmente igual (conecto a la misma BD, misma sentencia sql) en ese programa sí lo hace y en este no. Y no lo entiendo, ambos tienen permisos y todo igual, solo que el de prueba sólo busca el servicio en la tabla y me lo devuelve con un print.
En cuanto a lo de 'trama' me he confundido al escribirlo en el foro, pero lo tengo bien en el programa, ya la cagé una vez con eso y ya no se me olvida.
¿Que más puedo probar?
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-09-27 07:46 @365

Antes de ejecutar el SELECT, imprime en pantalla la instrucción SQL para ver qué es lo que va ha hacer. Hazlo en los dos programas y mira a ver si hay alguna diferencia.

Recuerda que puedes dialogar con MySQL desde la línea de comandos suya, a través del comando mysql.

Otra opción sería hacer un pequeño programa que sólo hiciera la conexión a la base de datos para comprobar realmente que la SELECT funciona, pero veo que no es necesario porque dices que ya te funciona en el otro programa.
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

Notapor Josmanue » 2006-09-28 02:21 @139

Esto no hay quien lo entienda, a ver, no paro de darle vueltas y yo Juraría que ambos programas estan exactamente iguales, cuando les meto la cadena de ejemplo:
'#0UIDSP103FEC060926TIE090000VALALAT5525,1234SLASLON12525,1234SLOEALT00895'
el programa que sale bien me devuelve:
Código: Seleccionar todo
Fuente:0
UID      SP103
FEC      060926
TIE      090000
VAL      A
LAT      5525,1234
SLA      S
LON      12525,1234
SLO      E
ALT      00895

La cadena sql tiene : INSERT INTO partes_3 SET Northing = '-9089209.99698948', longitud = '12525,1234E', fuente = '0', uid = 'SP103', validez = 'A', Easting = '5088.02311980753', latitud = '5525,1234S', altitud = '00895', dia = '060926', hora = '09:00:00';
En sth hay: DBI::st=HASH(0x81a2d98)
Y me devuelve el servicio correspondiente. Este es correcto, en cambio con el otro programa y ante la misma cadena me devuelve:
Código: Seleccionar todo
Fuente:0
ALT      00895

La cadena sql tiene: INSERT INTO partes_3 SET Northing = '0', longitud =' ', fuente ='0', latitud = ' ', Easting = '833991.704418281', altitud = '00895';
En sth hay: DBI::st=HASH(0x81adb08)

Y en este no devuelve el servicio. Parece que el problema está antes, ya que por arte de magia y sin haber tocado yo nada, resulta que ahora no extrae bien los campos, así, no obtiene el campo 'uid' y por tanto es imposible que me diga a que servicio corresponde.
¿¿Puedes echarme una mano??
El programa es el que está puesto un poco antes.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor Josmanue » 2006-09-28 05:32 @272

Vale ya se donde está el problema, pero necesito ayuda para resolverlo.
En el programa, en el bucle de "While (my @canal=....." justo después de "next unless...", en la version anterior ponía:
Código: Seleccionar todo
my($fuente,) = $trama =~ /^#(0|2)/;
$trama{FUE} = $fuente;
print "Fuente:$fuente\n";
Esto lo modificamos para que la cadena buscada pudiera estar en medio de otra cadena más larga, y lo cambiamos por:
Código: Seleccionar todo
my $fuente;
($fuente, $trama) = $trama =~ /(?:#(0|2)($campos)+)/;
$trama{FUE} = $fuente;
print "Fuente:$fuente\n";
Y ahí es donde falla, he cogido el programa que funcionaba y he empezado a añadirle cosas poco a poco y cuando he cambiado esto es cuando ha dejado de funcionar bien.
Lo dicho, no me caen nada bien las expresiones regulares. Alguna idea de cómo cambiarlo??
Gracias.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-09-28 06:16 @302

Efectivamente, había un error en la expresión regular.

Tal y como lo tenías puesto, sólo capturaba el último campo de la trama, cuando realmente necesitamos que capture todos los posibles.

Lo siguiente lo he probado y funciona:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    ## Lectura de la trama #############################################################
    my $linea = <>; #con esto leemos la cadena por la entrada estándar
    chomp $linea;   #y le quitamos el final de línea.
    #print "$linea\n";

    #Con esto sacamos el valor del campo "#" y lo almacenamos en $fuente
    #lo hago separado de los demas porque es el único campo que no empieza
    #con tres caracteres. El resto queda en $trama. Si no coincide, repetimos espera
    next unless my ($fuente, $trama) = $linea =~ /(?:#(0|2)((?:$campos)+))/;

    #print "Fuente:$fuente\n";
    #print "Trama: $trama\n";
    $trama{FUE} = $fuente;

    ## Bucle en el que recorremos los campos para identificarlos #######################
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Sólo tienes que sustituirlo en tu programa, entre las dos líneas de comentarios que lo delimitan.

De paso, hemos ahorrado un par de líneas :-)
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

Notapor Josmanue » 2006-09-29 04:51 @243

Muchisimas gracias explorer! ahora ya me funciona todo estupendamente :D :D . Ya empiezo a verle la punta a esto, de hecho espero poder terminarlo hoy mismo y empezar a probarlo (con tu ayuda, claro). El programa en sí está acabado pero ahora hay que añadirle algunas funciones más.
Primero debo distinguir entre dos cadenas recibidas, la cadena que hemos tratado hasta ahora y por otra parte la cadena '$uid', es decir el '$' seguido de los 5 caracteres del uid, por ejemplo: '$SP103'. Esta cadena es un especie de 'estoy vivo' que se envía cada 30 seg. ( el parte, (la cadena que tratábamos hasta ahora) puede tardar más en enviarse. Si recibe la cadena de siempre, ejecutará el programa, en cambio si recibe esta nueva cadena, entonces sólo preguntará si hay alguna orden para enviarle y ejecutamos la parte del envio de ordenes. Supongo que lo hago con un if pero (como siempre) no se muy bien que expresion regular tengo que poner o si hay que guardar esta cadena en alguna variable '@campos2' o algo así para sacar el campo UID.

Y por otra parte, tengo que completar el tratamiento de las ordenes, a ver si me explico bien porque es un poco lioso.

a) en el envío de ordenes falta actualizar el campo ack_orden de la tabla de 0 a 1, para ello una vez enviado, la maquina devolverá la cadena '@OC1uid', por ejemplo '@OC1SP103'. si el programa recibe esta cadena, entonces tengo que poner el campo ack_orden = '1'.
Vuelvo a no saber muy bien qué debo poner para identificar esa cadena.

b) El programa también debe recibir ordenes, con lo cual hay que hacer el tratamiento de otra cadena, y este creo que es el problema más grande, porque la cadena comienza igual que la otra, en este caso es:
#xUIDxxxxxFECxxxxxxTIExxxxxx@ODxxxxx@OTxxx@ORxxxx...@OPx
Cambia a partir de TIE, cuando llegue esta cadena debo insertar en la tabla ordenes
UID en origen_orden
FEC en fecha_recepcion
TIE en hora_recepcion
@OD en destino_orden
@OT en tipo_orden
@OR en orden (este campo tiene longitud variable, ya que es la orden en sí)
@OP en prioridad
¿Como puedo hacer para tratar esta nueva cadena?

Y con esto creo que terminaría el programa.
Se que es bastante largo y son varias cosas, espero que puedas echarme una mano en lo que puedas.
Gracias.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor Josmanue » 2006-09-29 06:51 @327

se podria preguntar por el caracter '@' ¿no?
si se encuentra en la trama leida entonces trato la cadena como orden, si no la trato como parte. ¿puede ser?
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-09-29 09:44 @447

Josmanue escribiste:Primero debo distinguir entre dos cadenas recibidas, la cadena que hemos tratado hasta ahora y por otra parte la cadena '$uid', es decir el '$' seguido de los 5 caracteres del uid, por ejemplo: '$SP103'. Esta cadena es un especie de 'estoy vivo' que se envía cada 30 seg. ( el parte, (la cadena que tratábamos hasta ahora) puede tardar más en enviarse. Si recibe la cadena de siempre, ejecutará el programa, en cambio si recibe esta nueva cadena, entonces sólo preguntará si hay alguna orden para enviarle y ejecutamos la parte del envio de ordenes. Supongo que lo hago con un if pero (como siempre) no se muy bien que expresion regular tengo que poner o si hay que guardar esta cadena en alguna variable '@campos2' o algo así para sacar el campo UID.

Quizás el programa tiene ya una cierta longitud y merecería la pena dividirlo en subrutinas, para hacerlo más fácil.
Lo que planteas ahora es podría esquematizar así:
Código: Seleccionar todo
Bucle de espera a recibir algo dentro de un tiempo
    Leer lo recibido
    Si lo recibido coincide con /\$SP103/,
        ejecutar 'estoy vivo'
    Si lo recibido coincide con una trama,
        ejecutar 'procesar trama'
    Si ...
Repetir Bucle

Lo que ya no dices es cómo sabemos que 'SP103' es el nombre del UID. Y tampoco qué hacer en caso de recibirlo.

Josmanue escribiste:Y por otra parte, tengo que completar el tratamiento de las ordenes,
  • en el envío de ordenes falta actualizar el campo ack_orden de la tabla de 0 a 1, para ello una vez enviado, la maquina devolverá la cadena '@OC1uid', por ejemplo '@OC1SP103'. si el programa recibe esta cadena, entonces tengo que poner el campo ack_orden = '1'.
    Vuelvo a no saber muy bien qué debo poner para identificar esa cadena.
  • El programa también debe recibir ordenes, con lo cual hay que hacer el tratamiento de otra cadena, y este creo que es el problema más grande, porque la cadena comienza igual que la otra, en este caso es:
    #xUIDxxxxxFECxxxxxxTIExxxxxx@ODxxxxx@OTxxx@ORxxxx...@OPx
    Cambia a partir de TIE, cuando llegue esta cadena debo insertar en la tabla ordenes
    Código: Seleccionar todo
    UID en origen_orden
    FEC en fecha_recepcion
    TIE en hora_recepcion
    @OD en destino_orden
    @OT en tipo_orden
    @OR en orden (este campo tiene longitud variable, ya que es la orden en sí)
    @OP en prioridad

    ¿Como puedo hacer para tratar esta nueva cadena?

Todo se basa en seguir metiendo expresiones regulares para identificar cadenas.
Hay un problema no comentado, me parece, y es que no estamos seguros de que las cadenas siempre estén separadas por los retornos de carro. Si lo están, entonces no hay problema para este tipo de bucles. Si no lo están, habría que añadir un bucle más dentro de este para procesar toda la línea leída.

Para el primer punto, creo que necesitas llevar un control de estado. Esto lo puedes hacer con una variable que 'recuerde' lo que se había recibido o hecho en un bucle anterior. Y con un if adecuado actuar de una manera o de otra.

Para el segundo punto, se trataría parecido al caso de $campos, pero en otra variable. El problema es el subcampo @OR, con la orden, al ser variable. En la expresión regular que tienes que poner para detectarlo, debes incluir algo como '\@OR[^@]+?' que quiere decir que busque la cadena '@OR' seguida de uno o más caracteres que no sean '@' ([^@]+), quedándonos con el caso más corto (?). Naturalmente esto sólo funcionará si al subcampo @OR le sigue otro campo que comience por '@' (y que dentro de la orden tampoco existan '@').
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

Notapor Josmanue » 2006-10-02 01:52 @119

Vayamos por partes, en cuanto a lo de que cómo sabemos que 'SP103' es el nombre del UID, la respuesta es "porque es así y punto", me explico, si recibes una cadena de 6 caracteres que empieza por '@' y va seguido por 5 caracteres, entonces, se trata de un "estoy vivo" y esos 5 caracteres son el UID de la máquina en cuestion. Y en este caso, hay que ver si existe alguna orden en la tabla ordenes para ese UID y enviarlo, cuando llegue el acuse de recibo de esta máquina (@OC1SP103) hay que colocar un '1' en el campo ack_orden de la tabla ordenes, con ello conseguimos que a los 30 segundos, cuando la máquina vuelva a enviar un 'estoy vivo', es decir, un '$SP103', el ack_orden esté a '1' y no le vuelvo a mandar la misma orden.

He estado mirando y creo que la sentencia SQL que tengo que usar es esta:
Código: Seleccionar todo
$sql2=("UPDATE ordenes SET ack_orden='1' WHERE destino_orden = 'UID'")
, pero claro, este 'UID' tengo que sacarlo de la cadena '$SP103' o de la cadena '@OC1SP103' y ahí es donde me quedo atascado.

En cuanto a lo de los retornos de carro, no había pensado en ello la verdad, luego lo consulto pero estoy casi seguro de que sí que van separadas cada cadena por retorno de carro.

Aquí pongo el que creo que es el esquema definitivo del programa.
Código: Seleccionar todo
while (my @canal = $s->can_read(180))
{

       ## Lectura de la trama #############################################################
        my $linea = <>; #con esto leemos la cadena por la entrada estándar
        chomp $linea;   #y le quitamos el final de línea.
        #print "$linea\n";
        if($linea = 'estoy vivo')
        {
           sacar su 'UID';
       si hay orden para ese 'UID' mandar la orden
        }
        else if($linea='@OC1SP103')
        {
       sacar su 'UID'
       actualizar ack_orden = '1' para ese 'UID'
        }
        else if($linea= #xUIDxxxxxFECxxxxxxTIExxxxxx@ODxxxxx@[email protected]@OPx)
        {
       separar los campos
       construir la sentencia sql para insertar los campos
       insertar los campos en la tabla ordenes
        }
        else
        {
       tratamiento de la trama
        }
}
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

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