• 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-08-09 07:04 @336

Jajajaja.... el fallo que todos hemos cometido alguna vez...

if ($trama{$SLA} = 'S')
if ($trama{$SLO} = 'W')

Deberia de ser...

if ( $trama{SLA} eq 'S')
if ( $trama{SLO} eq 'W')


También culpa mía... me he dado cuenta de que lo pusiste el 26 de julio y ni me dí cuenta... si es que es un fallo muy normal...

Otra cosa... queda muy espectacular todo el cálculo y está genial ponerlo para aprender.

Yo, como soy mayor, usaría
Código: Seleccionar todo
use Geo::Coordinates::UTM;
my ($zona,$easting,$northing)=latlon_to_utm("International",$latitud,$longitud);

Pero repito... está muy bien hacerlo todo uno mismo.

Ya lo veo: te falta algo de dinero...

$sql .= join( ', ', map { "$_ = \'$trama{_}\'" } keys %trama );

debería de ser

$sql .= join( ', ', map { "$_ = \'$trama{$_}\'" } keys %trama );

La mayoría de todos estos fallos nos los ahorraríamos si usáramos use warnings; al principio. Y con use strict;, mejor.

Josmanue escribiste:Un pequeño detalle más, que me acabo de dar cuenta, los campos dentro de la base de datos no tienen exactamente el mismi nombre que los campos que vienen en la cadena, por ejemplo,
el campo TIE corresponde al campo 'dia' de la BD
el campo VAL corresponde al campo 'validez' de la BD
LAT es 'latitud'
.....

Así que a la hora de construir la sentencia del INSERT tengo que cambiar esos nombres no? si no no me los va a reconocer.
Sí... y es un rollo... yo lo haría en el bucle donde lees los campos. Si lees un campo de esos, lo que haces entonces es meter en %trama una clave distinta con ese valor. Así no tienes que tocar nada después... Bueno, es una opción...
Última edición por explorer el 2006-08-09 08:10 @382, editado 6 veces en total
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-08-10 04:00 @208

Hola, ya he resumido todos mis comentarios, aunq he intentado borrarlos pero no se como, no hay ninguna opcion de eliminar.
Así que he pagado la novatada del 'eq' no? que pardillo!

a ver, resulta que la mayoría de los campos tienen nombre diferente en la base de datos, así que creo que lo voy a hacer un poco a lo bestia.
He puesto:
Código: Seleccionar todo
#Preparacion de la cadena INSERT:
$uid = $trama{UID};
$dia = $trama{FEC};
$hora = $trama{TIE};
$validez = $trama{VAL};
$latitud = $trama{LAT}.$trama{SLA};
$longitud = $trama{LON}.$trama{SLO};
$altitud = $trama{ALT};
$velocidad = $trama{VEL};
$direccion = $trama{DIR};
$temperatura = $trama{TEM};
$humedad = $trama{HUM};
$vel_viento = $trama{VIV};
$dir_viento = $trama{VID};
$veleta = $trama{VIE};
$nivel_agua = $trama{NIV};
$nivel_gasoil = $trama{NIG};
$punto_sing = $trama{PTO};

$sql2 = "INSERT INTO partes_3 SET fuente = '$fuente', uid = '$uid', dia = '$dia', hora = '$hora', validez = '$validez', latitud = '$latitud',
longitud = '$longitud', altitud = '$altitud', velocidad = '$velocidad', direccion = '$direccion', temperatura = '$temperatura', humedad = '$humedad',
vel_viento = '$vel_viento', dir_viento = '$dir_viento', veleta = '$veleta', nivel_agua = '$nivel_agua', nivel_gasoil = '$nivel_gasoil',
punto_sing = '$punto_sing', Easting = '$Easting', Northing = '$Northing'";

print "La cadena sql2 tiene: $sql2\n";


Y elimino las 3 lineas:
Código: Seleccionar todo
$sql = 'INSERT INTO partes_3 SET ';
$sql .= join( ', ', map { "$_ = \'$trama{$_}\'" } keys %trama );
$sql .= ';';

print " la cadena sql tiene: $sql\n";


Puedo hacerlo ¿verdad? La cadena queda igual desde luego.

Por otra parte he estado mirando lo que me diste de las bases de datos y tengo una pregunta. ¿Hay que crear obligatoriamente el módulo que crean ahi? (ConectarDB) o puedo poner directamente el código dentro del programa??
No me gustaría liar más la perdiz con módulos y esas cosas si eso puede ser.
Gracias.

Ah! $latitud y $longitud no estan mal, a la hora de insertarlos en la BD tienen que ir concatenados con SLA y SLO respectivamente.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-08-10 05:05 @253

Recuerda: cada vez que tengas que hacer la misma operación más de 5 veces seguidas, piensa que hay una forma más cómoda de hacerlo. Si hay que hacer lo mismo muchas veces, es que necesitamos una combinación de bucles y arrays/hashes.
Código: Seleccionar todo
my %campos_bd = (
    UID => 'uid', FEC => 'dia', TIE => 'hora', VAL => 'validez',
    LAT => 'latitud', LON => 'longitud', ALT => 'altitud',
    VEL => 'velocidad', DIR => 'direccion', TEM => 'temperatura',
    HUM => 'humedad', VIV => 'vel_viento', VID => 'dir_viento',
    NIV => 'nivel_agua', NIG => 'nivel_gasoil', PTO => 'punto_sing',
);
y luego, después del bucle de lectura de los campos, agregas el ajuste para los campos latitud y longitud. Y luego, a la hora de hacer la $sql:
Código: Seleccionar todo
$sql = 'INSERT INTO partes_3 SET ';
$sql .= join( ', ', map { "$campos_bd{$_} = \'$trama{$_}\'" } keys %trama );
$sql .= ';';

print " la cadena sql tiene: $sql\n";

Podría parecer que es casi lo mismo de largo que la solución anterior tuya y casi es cierto, pero agrupando la información en estructuras de datos nos protegemos más frente a posibles errores que hayamos podido cometer.
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-08-10 05:56 @289

Ya ya, me lo suponía, pero quería construir una cadena aunque fuera "a lo bestia" y así empezar a probar si se inserta en la Base de datos o no y hacer algunas pruebas. Porque en el tutorial no parece dificil, pero tengo algunas dudas acerca de eso:

¿Necesito crear realmente el módulo como dicen ahi?

En la sentencia del 'prepare', ¿Necesito poner un "campo = ?" por cada campo que tengo que insertar?

¿Necesito hacer realmente el lo del 'prepare'? Porque la sentencia $sql ya está "preparada" con todos los campos y sus respectivos valores.

¿Acabaremos algún día este programa? :lol: je jeje.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-08-10 07:22 @349

Josmanue escribiste:¿Necesito crear realmente el módulo como dicen ahi?
No.

Josmanue escribiste:En la sentencia del 'prepare', ¿Necesito poner un "campo = ?" por cada campo que tengo que insertar?
No

Josmanue escribiste:¿Necesito hacer realmente el lo del 'prepare'? Porque la sentencia $sql ya está "preparada" con todos los campos y sus respectivos valores.
Pues eso, la metes en el prepare y luego haces el execute()...

O mejor... olvidate del prepare+execute... haz un do();
Código: Seleccionar todo
$filas = $dbh->do($sql)           or die $dbh->errstr;
sacado del manual del DBI. ¿Has visto que útil es a veces leer el manual?

Josmanue escribiste:¿Acabaremos algún día este programa? :lol: je jeje.
Voy a actualizar mi lista de precios... :-)
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-08-11 06:51 @327

La cadena $sql tiene:
INSERT INTO partes_3 SET = ' ', uid = 'trg02', direccion = '045', vel_viento = '017', nivel_gasoil = '065', = '1', = '5525,1234', hora = 09:00:00', nivel_agua '09561', = '12525,1234', = 'S', validez = 'A', punto_sing = '1', temperatura = '031', = 'E', velocidad = '080', humedad = '055', dir_viento = '300', altitud = '00895', dia = '060825';, fuente = '0', Easting = '-8123449.08950206', Northing = '9089641.39307333', latitud = '5525,1234S', longitud = '12525,1234E

Puede ser del ";" de después de "dia = '060825'"?

Yo lo único que he hecho es eliminar dentro de "my %campos_bd" que me dijiste, los campos LAT y LON para después añadir los modificados.
Y después:
Código: Seleccionar todo
$sql.= ", fuente = '$fuente', Easting = '$Easting', Northing = '$Northing', latitud ='$latitud', longitud = '$longitud'";

Aki el último apóstrofe tambien faltaba, ya se lo he puesto.
Josmanue
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2006-06-09 04:33 @231

Notapor explorer » 2006-08-17 09:34 @440

De momento, he visto que no has corregido un problema ya comentado antes:
if ($trama{$SLA} eq 'S')
es
if ($trama{SLA} eq 'S')

Y lo mismo para SLO.

Ahora miro el resto...
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 explorer » 2006-08-17 12:45 @573

Hay algunos errores de cálculo que he descubierto...
* P1CosLat no es inicializada en ningún sitio, por lo que el cálculo de $East_Term1 puede ser erróneo.
* En el cálculo del valor de LON, usas la variable $mmmmm, cuando en realidad debería ser la $mmmm.
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 explorer » 2006-08-17 13:43 @613

Ya está...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
# Traductor de tramas

### Librerías
use DBI;

### Modos
use warnings;
use strict;

### Definición de variables #########################################
## Base de datos
my $database = "database";
my $host     = "hostname.com";
my $port     = 3306;
my $user     = "username";
my $password = "password";

## Cálculo de las posiciones UTM
my ($Latitud_Grados, $Longitud_Grados);
my ($Latitud_Rad, $Longitud_Rad);
my ($Northing,$Easting);
my ($East_Term1, $East_Term2, $East_Term3, $East_Term4);
my ($North_Term1, $North_Term2, $North_Term3, $North_Term4);
my ($MeridianDistance, $Meridian);
my $Nu;
my ($P1_CosLat, $P1_DiffLong, $P1_Psi, $P1_TanLat);
my ($P2_CosLat, $P2_DiffLong, $P2_Psi, $P2_TanLat);
my ($P3_CosLat, $P3_DiffLong, $P3_Psi,           );
my ($P4_CosLat, $P4_DiffLong, $P4_Psi, $P4_TanLat);
my ($P5_CosLat, $P5_DiffLong,                    );
my ($P6_CosLat, $P6_DiffLong,          $P6_TanLat);
my ($P7_CosLat, $P7_DiffLong,                    );
my (            $P8_DiffLong,                    );
my ($A0, $A2, $A3, $A4, $A6);
my ($Eccentricity, $Flattening, $SemiMinorAxis, $SegEccentricity);
my ($Radii, $Rho);
my ($CentMeridZona0, $CentralMeridian, $ZoneNum);
my $LongOesteZona0;
my ($MD_Term1, $MD_Term2, $MD_Term3, $MD_Term4);
my $Pi = 3.14159265358979;
my $Huso = 30;
my $InverseFlattening = 297;
my $FalseEasting = 500000;
my $FalseNorthing = 0;
my $MeridianOfZone1 = -177;
my $SemiMajorAxis = 6378388;
my $CentralEscaleFactor = 0.9996;
my $ZoneWidth = 6;

## Especiales
$|++;

### Subrutinas ######################################################
sub tan { sin($_[0]) / cos($_[0]) }

### Programa ########################################################
my %trama;

## Conexión a la base de datos
my $dsn = "DBI:mysql:database=$database;host=$host;port=$port";
my $dbh = DBI->connect($dsn,$user,$password)
    or die $DBI::errstr;

## Expresiones regulares a buscar en la trama
#definimos @campos como una lista de expresiones regulares,
#que son el nombre de cada campo con la correspondiente longitud
#de su valor.
my @campos = qw(
    UID.{5}         FEC.{6}     TIE.{6}         VAL.
    LAT.{4},.{4}    SLA.        LON.{5},.{4}    SLO.
    ALT.{5}         VEL.{3}     DIR.{3}         TEM.{3}
    HUM.{3}         VIV.{3}     VID.{3}         VIE.
    NIV.{5}         NIG.{3}     PTO.
);

#definimos $campos como la union de todo eso separado con '|',
#que es la 'or' de una expresion regular
my $campos = join('|', @campos);

## Lectura de la trama
my $trama = <>; #con esto leemos la cadena por la entrada estándar
chomp $trama;   #y le quitamos el final de línea.
#print "$trama\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.
my ($fuente) = $trama =~ /^#(0|2)/;
$trama{FUE} = $fuente;
#print "Fuente:$fuente\n";

## Bucle en el que recorremos los campos para identificarlos
while ( $trama =~/($campos)/g )
{
    my ($campo, $valor) = unpack( "A3 A*", $1);
    print "\t$campo\t$valor\n";

    # Ajuste de valores según el campo
    if ($campo eq 'LAT' or $campo eq 'LON')
    {
        my ($GG,$MM,$mmmm) = $valor =~ /(...?)(..),(....)/;
        my $grados = $GG + $MM/60 + $mmmm/600000;
        $Latitud_Grados  = $grados if $campo eq 'LAT';
        $Longitud_Grados = $grados if $campo eq 'LON';
    }
    if ($campo eq 'TIE') { $valor = join(':', $valor =~ /(..)/g) }

    # Lo guardamos
    $trama{$campo} = $valor;
}

#Y los paso a negativos si se cumple la condicion necesaria:
if ($trama{SLA} eq 'S') { $Latitud_Grados  = -$Latitud_Grados  }
if ($trama{SLO} eq 'W') { $Longitud_Grados = -$Longitud_Grados }

#valores definitivos de latitud y longitud
$trama{LAT} .= $trama{SLA};
$trama{LON} .= $trama{SLO};

print " Latitud  en Grados es: $Latitud_Grados\n";
print " Longitud en Grados es: $Longitud_Grados\n";
print " La hora es: $trama{TIE}\n";

#Conversion de coordenadas:
#Parametros derivados del elipsoide:

$LongOesteZona0 = $MeridianOfZone1 -(1.5*$ZoneWidth);
$CentMeridZona0 = $LongOesteZona0 + ($ZoneWidth/2);
$Flattening = 1/$InverseFlattening;
$SemiMinorAxis = $SemiMajorAxis + (1-$Flattening);
$Eccentricity = (2*$Flattening) - ($Flattening * $Flattening);
$SegEccentricity = $Eccentricity/(1-$Eccentricity);
my $n = ($SemiMajorAxis - $SemiMinorAxis)/($SemiMajorAxis + $SemiMinorAxis);
my $G = ($SemiMajorAxis*(1-$n)*(1-$n*$n)*(1+(9*$n*$n)/4+(225*$n*$n*$n*$n)/64)*$Pi/180);
$A0 = (1-($Eccentricity/4)-((3*$Eccentricity*$Eccentricity)/64)-((5*$Eccentricity*$Eccentricity*$Eccentricity)/256));
$A2 = ((3/8)*($Eccentricity+($Eccentricity*$Eccentricity/4)+((15*$Eccentricity*$Eccentricity*$Eccentricity)/128)));
$A4 = ((15/256)*($Eccentricity*$Eccentricity+((3*$Eccentricity*$Eccentricity*$Eccentricity)/4)));
$A6 = (35*($Eccentricity*$Eccentricity*$Eccentricity))/3072;

$Latitud_Rad = $Latitud_Grados/180*$Pi;
$Longitud_Rad = $Longitud_Grados/180*$Pi;

$ZoneNum = ($Longitud_Grados - $LongOesteZona0)/$ZoneWidth;
$CentralMeridian = $Huso*$ZoneWidth+$CentMeridZona0;

#Meridian Distance:

$MD_Term1 = $SemiMajorAxis*$A0*$Latitud_Rad;
$MD_Term2 = -$SemiMajorAxis*$A2*(sin(2*$Latitud_Rad));
$MD_Term3 = $SemiMajorAxis*$A4*(sin(4*$Latitud_Rad));
$MD_Term4 = -$SemiMajorAxis*$A6*(sin(6*$Latitud_Rad));
$MeridianDistance = $MD_Term1+$MD_Term2+$MD_Term3+$MD_Term4;

#Radii of Curvature:

$Rho = $SemiMajorAxis*(1-$Eccentricity)/(1-$Eccentricity*(sin($Latitud_Rad))*(sin($Latitud_Rad)))**1.5;
$Nu = $SemiMajorAxis/(1-($Eccentricity*(sin($Latitud_Rad))*(sin($Latitud_Rad))))**0.5;

#Powers:

$P1_CosLat = cos($Latitud_Rad);
$P2_CosLat = $P1_CosLat*$P1_CosLat;
$P3_CosLat = $P1_CosLat*$P2_CosLat;
$P4_CosLat = $P2_CosLat*$P2_CosLat;
$P5_CosLat = $P2_CosLat*$P3_CosLat;
$P6_CosLat = $P3_CosLat*$P3_CosLat;
$P7_CosLat = $P6_CosLat*$P1_CosLat;
$P1_DiffLong = (($Longitud_Grados-$CentralMeridian)/180)*$Pi;
$P2_DiffLong = $P1_DiffLong*$P1_DiffLong;
$P3_DiffLong = $P2_DiffLong*$P1_DiffLong;
$P4_DiffLong = $P2_DiffLong*$P2_DiffLong;
$P5_DiffLong = $P3_DiffLong*$P2_DiffLong;
$P6_DiffLong = $P3_DiffLong*$P3_DiffLong;
$P7_DiffLong = $P6_DiffLong*$P1_DiffLong;
$P8_DiffLong = $P4_DiffLong*$P4_DiffLong;
$P1_TanLat = tan($Latitud_Rad);
$P2_TanLat = $P1_TanLat*$P1_TanLat;
$P4_TanLat = $P2_TanLat*$P2_TanLat;
$P6_TanLat = $P4_TanLat*$P2_TanLat;
$P1_Psi = $Nu/$Rho;
$P2_Psi = $P1_Psi*$P1_Psi;
$P3_Psi = $P2_Psi*$P1_Psi;
$P4_Psi = $P2_Psi*$P2_Psi;

#Easting:
$East_Term1 = $Nu*$P1_DiffLong*$P1_CosLat;
$East_Term2 = $Nu*$P3_DiffLong*$P3_CosLat*($P1_Psi-$P2_TanLat)/6;
$East_Term3 = $Nu*$P5_DiffLong*$P5_CosLat*(4*$P3_Psi*(1-6*$P2_TanLat)+$P2_Psi*(1+8*$P2_TanLat)-$P1_Psi*(2*$P2_TanLat)+$P4_TanLat)/120;
$East_Term4 = $Nu*$P7_DiffLong*$P7_CosLat*(61-479*$P2_TanLat+179*$P4_TanLat-$P6_TanLat)/5040;

$Easting = ($East_Term1 + $East_Term2 + $East_Term3 + $East_Term4)*$CentralEscaleFactor + $FalseEasting;

$trama{EAS} = $Easting;

#Northing:
$North_Term1 = $Nu*sin($Latitud_Rad)*$P2_DiffLong*$P1_CosLat/2;
$North_Term2 = $Nu*sin($Latitud_Rad)*$P4_DiffLong*$P3_CosLat*(4*$P2_Psi+$P1_Psi-$P2_TanLat)/24;
$North_Term3 = $Nu*sin($Latitud_Rad)*$P6_DiffLong*$P5_CosLat*(8*$P4_Psi*(11-24*$P2_TanLat)-28*$P3_Psi*(1-6*$P2_TanLat)+$P2_Psi*(1-32*$P2_TanLat)-$P1_Psi*(2*$P2_TanLat)+$P4_TanLat)/720;
$North_Term4 = $Nu*sin($Latitud_Rad)*$P8_DiffLong*$P7_CosLat*(1385-3111*$P2_TanLat+543*$P4_TanLat-$P6_TanLat)/40320;

$Northing = ($MeridianDistance + $North_Term1 + $North_Term2 + $North_Term3 + $North_Term4)*$CentralEscaleFactor + $FalseNorthing;

$trama{NOR} = $Northing;

## Preparacion de la cadena INSERT:
# Campos que leeremos de %trama
my %campos_bd = (
    UID => 'uid',       FEC => 'dia',           TIE => 'hora',      VAL => 'validez',
    ALT => 'altitud',   VEL => 'velocidad',     DIR => 'direccion', TEM => 'temperatura',
    HUM => 'humedad',   VIV => 'vel_viento',    VID => 'dir_viento',VIE => 'veleta',
    NIV => 'nivel_agua',NIG => 'nivel_gasoil',  PTO => 'punto_sing',
    LAT => 'latitud',   LON => 'longitud',
    EAS => 'Easting',   NOR => 'Northing',      FUE => 'fuente',
);

my $sql ='INSERT INTO partes_3 SET ';
$sql   .= join( ', ',
            map  { "$campos_bd{$_} = \'$trama{$_}\'" }
            grep {      defined $campos_bd{$_}       }
            keys %trama
          );
$sql   .= ';';

print " la cadena sql tiene: $sql\n";

## Guardar en base de datos
my $filas = $dbh->do($sql)
    or die $dbh->errstr;

__END__
Coloreado en 0.010 segundos, usando GeSHi 1.0.8.4

Dada la trama
#0UIDcami2FEC060825TIE090000VALALAT2525,1234SLANLON12525,1234SLOEALT00895VEL080
la salida es:
Código: Seleccionar todo
        UID     cami2
        FEC     060825
        TIE     090000
        VAL     A
        LAT     2525,1234
        SLA     N
        LON     12525,1234
        SLO     E
        ALT     00895
        VEL     080
 Latitud  en Grados es: 25.4187233333333
 Longitud en Grados es: 125.418723333333
 La hora es: 09:00:00
 la cadena sql tiene: INSERT INTO partes_3 SET Northing = '48528990.2692927', longitud = '12525,1234E', fuente = '0',
 uid = 'cami2', validez = 'A', Easting = '15370470.0438008', velocidad = '080', latitud = '2525,1234N', altitud = '00895',
 dia = '060825', hora = '09:00:00';

Lo que he hecho es arreglar algunos problemas con algunas varaibles, gracias a la ayuda de use strict;. Luego, he unificado algunas cosas, como la lectura y cálculo de la longitud y latitud. Y finálmente, he unificado la creación del INSERT, con lo que, además de abreviar el programa, nos ahorramos algunos errores (ya se sabe... cuanto más corto es el programa menos probabilidad de cometer un error :-))
Última edición por explorer el 2006-08-27 22:35 @982, editado 2 veces en total
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 explorer » 2006-08-17 14:13 @634

Y esta es la versión con el módulo Geo::Coordinates::UTM. La ventaja de usar este módulo, aparte del montón de líneas que te ahorras, es que no tienes que preocuparte de mirar los coeficientes del cálculo, como por ejemplo, saber en qué uso o zona se está haciendo el cálculo.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use DBI;
use Geo::Coordinates::UTM;

## Conexión a la base de datos
my $database = "database";
my $host     = "hostname.com";
my $port     = 3306;
my $user     = "username";
my $password = "password";
my $dsn = "DBI:mysql:database=$database;host=$host;port=$port";
my $dbh = DBI->connect($dsn,$user,$password)
    or die $DBI::errstr;

## Variables generales
my ($Latitud_Grados, $Longitud_Grados);
my %trama;

## Lectura de la trama
my $trama = <>; #con esto leemos la cadena por la entrada estándar
chomp $trama;   #y le quitamos el final de línea.

#Con esto sacamos el valor del campo "#" y lo almacenamos en $fuente
my ($fuente) = $trama =~ /^#(0|2)/;
$trama{FUE} = $fuente;

## Expresiones regulares a buscar en la trama
my @campos = qw(
    UID.{5}         FEC.{6}     TIE.{6}         VAL.
    LAT.{4},.{4}    SLA.        LON.{5},.{4}    SLO.
    ALT.{5}         VEL.{3}     DIR.{3}         TEM.{3}
    HUM.{3}         VIV.{3}     VID.{3}         VIE.
    NIV.{5}         NIG.{3}     PTO.
);
my $campos = join('|', @campos);

## Bucle en el que recorremos los campos para identificarlos
while ( $trama =~/($campos)/g ) {
    my ($campo, $valor) = unpack( "A3 A*", $1);

    if ($campo eq 'LAT' or $campo eq 'LON') {
        my ($GG,$MM,$mmmm) = $valor =~ /(...?)(..),(....)/;
        my $grados = $GG + $MM/60 + $mmmm/600000;
        $Latitud_Grados  = $grados if $campo eq 'LAT';
        $Longitud_Grados = $grados if $campo eq 'LON';
    }
    if ($campo eq 'TIE') { $valor = join(':', $valor =~ /(..)/g) }

    $trama{$campo} = $valor;
}

#Y los paso a negativos si se cumple la condicion necesaria:
if ($trama{SLA} eq 'S') { $Latitud_Grados  = -$Latitud_Grados  }
if ($trama{SLO} eq 'W') { $Longitud_Grados = -$Longitud_Grados }

#valores definitivos de latitud y longitud
$trama{LAT} .= $trama{SLA};
$trama{LON} .= $trama{SLO};

print " Latitud  en Grados es: $Latitud_Grados\n";
print " Longitud en Grados es: $Longitud_Grados\n";
print " La hora es: $trama{TIE}\n";

my ($zona, $easting, $northing) = latlon_to_utm(
    "International",
    $Latitud_Grados, $Longitud_Grados
);
$trama{EAS} = $easting;
$trama{NOR} = $northing;

## Preparacion de la cadena INSERT:
# Campos que leeremos de %trama
my %campos_bd = (
    UID => 'uid',       FEC => 'dia',           TIE => 'hora',
    VAL => 'validez',   ALT => 'altitud',       VEL => 'velocidad',
    DIR => 'direccion', TEM => 'temperatura',   HUM => 'humedad',
    VIV => 'vel_viento',VID => 'dir_viento',    VIE => 'veleta',
    NIV => 'nivel_agua',NIG => 'nivel_gasoil',  PTO => 'punto_sing',
    LAT => 'latitud',   LON => 'longitud',
    EAS => 'Easting',   NOR => 'Northing',      FUE => 'fuente',
);

my $sql = 'INSERT INTO partes_3 SET ';
$sql   .= join( ', ',
            map  { "$campos_bd{$_} = \'$trama{$_}\'" }
            grep {      defined $campos_bd{$_}       }
            keys %trama
          );
$sql   .= ';';
#print " la cadena sql tiene: $sql\n";

## Guardar en base de datos
my $filas = $dbh->do($sql)
    or die $dbh->errstr;

__END__
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

Con este programa se obtienen 'casi' los mismos valores que con el primero.
Probando con latitud 41º00'00" y latitud -4º00'00", se obtiene para el primero:
Northing = '4539317.70889755'
Easting = '415894.042292828'
y para el segundo
Northing = '4539317.70897612'
Easting = '415894.042293205'

Eso quiere decir que hay una 'pequeña' diferencia de... diezmilésimas de metro :-)

Un detalle... aunque estás usando los datos del esferoide "International", quizás el mejor sea el "WGS-84". De eso ya no estoy tan seguro. Al menos, era el que nosotros usábamos siempre.
Última edición por explorer el 2006-08-27 22:36 @983, editado 1 vez en total
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

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

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