• Publicidad

Modification of a read-only value attempted

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

Modification of a read-only value attempted

Notapor natxo » 2010-01-12 13:52 @619

Buenas:

Quiero convertir un archivo csv a otro formato y al intentar cambiar un valor me da el error del título:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5. use Text::CSV_XS;
  6.  
  7. my $csvobj = Text::CSV_XS->new();
  8.  
  9. my $csvfile = "/tmp/test.csv";
  10.  
  11. open CSV, "<", $csvfile or die "cannot open $csvfile: $!\n";
  12.  
  13. # let's parse the file
  14. while (<CSV>) {
  15.     next if !/\S/ ; # skip blank lines
  16.  
  17.     $csvobj->parse($_) or die "can't parse: ". $csvobj->error_input();
  18.     my @fields = $csvobj->fields;
  19.  
  20.     # the date field is in this format: 20040231
  21.     if ( $fields[0] =~ /(\d{4})(\d{2})(\d{2})/ ) {
  22.         $1 = tr/2/a/d;
  23.         print $1, "\n";
  24.         }
  25. }
  26.  
  27. close CSV;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


y el archivo csv es de este tipo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
"20080731","1770001 381 xxxx xxxx>xxxx","xxxxxx","xxxxx","BA","Af","41,13","Betaalautomaat","PASNR ***xxxx 31-07-2008 19:01TRANSACTIENR xxxxx       "
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


El formato de la fecha del primer campo csv es yyyymmdd y yo necesito yy-mm-dd, por eso intento usar la función tr/// para cambiar el valor de $1, pero el resultado no es el deseado. El pragma diagnostics me dice que estoy intentando cambiar una constante. Sin embargo, no logro solucionar este problema.

¿Alguna idea?

TIA.
saludos,
Natxo Asenjo
natxo
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2007-08-09 16:22 @723
Ubicación: Países Bajos

Publicidad

Re: Modification of a read-only value attempted

Notapor explorer » 2010-01-12 14:08 @630

No puedes modificar el valor de $1, por ser una variable especial.

Prueba con un paso intermedio (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ( $fields[0] =~ /(\d{4})\d{2}\d{2})/ ) {
  2.     my $fecha = $1;
  3.     $fecha =~ tr/2/a/d;
  4.     print "$fecha\n";
  5. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y me parece el tr/// no es el correcto... yo usaría un substr($fecha,2).

Actualización: Se me ocurre algo... no es necesario el if() porque se supone que todas las líneas tienen una fecha como primer campo. Si es así, queda más corto haciéndolo así (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $fields[0] =~ /\d{2}(\d{2})(\d{2})(\d{2})/;
  2. my $fecha = "$1-$2-$3";
  3. print "$fecha\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
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: Modification of a read-only value attempted RESUELTO

Notapor natxo » 2010-01-12 16:20 @722

Perfecto, gracias. Con los dos métodos probados, tanto con substr() como con la separación del valor en cuatro cachos en vez de tres.

Explorer: cuando se ve la solución, hasta parece fácil y todo ;-)
saludos,
Natxo Asenjo
natxo
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2007-08-09 16:22 @723
Ubicación: Países Bajos

Re: Modification of a read-only value attempted

Notapor salva » 2010-01-12 17:29 @770

A mí me gusta más aprovecharme de que cuando el matching de la expresión regular se realiza en contexto de lista este devuelve la lista de capturas las cuales se pueden asignar a variables con nombres más expresivos:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my ($anno, $mes, $dia) = $fields[0] =~ /\d\d(\d\d)(\d\d)(\d\d)/;
my $fecha = "$anno-$mes-$dia";
print "$fecha\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

o incluso...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if (my ($anno, $mes, $dia) = $fields[0] =~ /\d\d(\d\d)(\d\d)(\d\d)/) {
  my $fecha = "$anno-$mes-$dia";
  print "$fecha\n";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La verdad es que ya casi nunca uso $1, $2, etc.
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

Re: Modification of a read-only value attempted

Notapor explorer » 2010-01-12 19:38 @860

Yo solía usar la segunda forma, porque es mucho más corta y expresiva, desde luego.

Lo que pasa es que en una ocasión me falló. Y dejé de usarla completamente.

Fue un caso similar a este:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $x = q[La donna e mobile cua piuma al vento];

if (my ($a, $b, $c) = $x =~ /(La) .* (cua) .* (viento)?/) {
    print "[$a] [$b] [$c]\n";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Bueno, se ve que la expresión regular captura las dos primeras concordancias y las deja en $a y $b, pero la tercera fallará ('vento' ne 'viento'). Entonces, el if() debería fallar (no hemos capturado las 3 variables), pero no lo hace, porque la expresión regular sí que ha funcionado: la tercera captura es opcional (el '?' del final). $c obtiene el valor de indefinido y así sale en pantalla.

Bueno, el caso es que Perl hace exactamente lo que se le pide. La expresión regular es correcta y coloca bien las variables... pero... no es precisamente "así" como quiero que se comporte... yo hubiese preferido que el if() fallara por no haber podido capturar todas las variables.

Sí, ya sé que entonces la culpa es mía porque tendría que poner una mejor expresión regular, pero en estos casos en que alguna captura es opcional, pues el my() puede engañar al if().

De hecho, lo siguiente tampoco será correcto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if (my ($a, $b, $c) = $x =~ /(La) .* (cua)/) {
    print "[$a] [$b] [$c]\n";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Ahora ni siquiera hay una opción de captura... simplemente hay menos capturas. Y aún así, el if() sigue adelante porque my() funcionó.

Tal cual está escrito, parecería que el if() debería ser correcto si se reciben los tres valores en las tres variables, pero my() devuelve 2, que es verdadero. Y el if(), entra.

La solución, es algo muy feo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if ( 3 == (my ($a, $b, $c) = $x =~ /(La) .* (cua) .* (vento)?/) ) {
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Pero eso sí, estoy de acuerdo que, en situaciones normales, lo ideal es usarlo.

El caso es que es un trauma infantil (y tonto) del que me tengo que curar, así que me tendré que poner las pilas y usarlo más a menudo (mirando con atención a la exp. reg., claro).
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: Modification of a read-only value attempted

Notapor salva » 2010-01-13 04:08 @214

explorer escribiste:El caso es que es un trauma infantil (y tonto) del que me tengo que curar, así que me tendré que poner las pilas y usarlo más a menudo (mirando con atención a la exp. reg., claro).
Bueno, ahora que perl 5.10 ya esta más o menos extendido, puede ser el momento de empezar a usar las named captures.
Avatar de Usuario
salva
Perlero nuevo
Perlero nuevo
 
Mensajes: 200
Registrado: 2008-01-03 15:19 @680

Re: Modification of a read-only value attempted

Notapor natxo » 2010-01-13 06:08 @297

salva escribiste:A mí me gusta más aprovecharme de que cuando el matching de la expresión regular se realiza en contexto de lista este devuelve la lista de capturas las cuales se pueden asignar a variables con nombres más expresivos:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my ($anno, $mes, $dia) = $fields[0] =~ /\d\d(\d\d)(\d\d)(\d\d)/;
my $fecha = "$anno-$mes-$dia";
print "$fecha\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

o incluso...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if (my ($anno, $mes, $dia) = $fields[0] =~ /\d\d(\d\d)(\d\d)(\d\d)/) {
  my $fecha = "$anno-$mes-$dia";
  print "$fecha\n";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La verdad es que ya casi nunca uso $1, $2, etc.


muy buena idea, la voy a usar a partir de ahora, gracias.
saludos,
Natxo Asenjo
natxo
Perlero nuevo
Perlero nuevo
 
Mensajes: 76
Registrado: 2007-08-09 16:22 @723
Ubicación: Países Bajos


Volver a Básico

¿Quién está conectado?

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