stavros has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

i need your help in a small programme that i want to create. i have a file which contain the following

name1 1481.100 1436.550 1460.410 1444.460 1049.120 1076.890 1085.500 1 +053.100 name2 1978.700 1949.910 1734.030 1694.530 1930.000 2005.530 1696.960 1 +844.810 name3 ...

and i want to write it as it is in a new file by only replacing the values with log(value)

so i use this programme

my $Name = ""; my $Value1 = 0; my @files = glob ('*.txt'); sub log10 { my $n = shift; return log($n)/log(10); } open (MYFILE, '>data.txt'); foreach my $file (@files) { #print "$file\n"; $test = "$file"; open (TEST,"$test") || die "couldn't open the file YEASTFASTA:$!"; while (<TEST>) { my $line = $_; if ($_=~/^\d+[_]\w+\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+.*/) { #$Name = $1; $Value1 = $2; $LogValue = log10($Value1); print MYFILE "$LogValue"; #print "d $LogValue \n"; } print MYFILE "$_"; } close TEST || die "can't close:$!"; close (MYFILE); }

and the output i take is

1.37852508154491 name1 23.907 15.022 25.234 22.573 21.541 13.972 25.07 +6 17.099 YLR331C 3.17058438193919 name2 1481.100 1436.550 1460.410 1444.460 1049.120 10 +76.890 1085.500 1053.100

so my point is how can i place the value 1.3785250815449 (which is the log(23.907)) not in the begging of the line but instead of the value 23.907, that means that i want this output

name1 1.3785250815449 log(value) log(value)...(log of all the values) name1 log(value) log(value)...(log of all the values)

Thanks in advance for your time.

Replies are listed 'Best First'.
Re: Writing file
by ambrus (Abbot) on Jun 23, 2011 at 18:36 UTC

    You're on the right track. However, you should use the regex to extract not only the value you want to change but also the rest of the line you don't wish to change, such as

    if (/^(\S+\s+)(\S+)(\s.*)/) { print $1 . log10($2) . $3 . "\n"; }
    or like this:
    my($name, $num, $rest) = split " ", $_, 3; print $name . " " . log10($num) . " " . $rest;

    Update: I see now that you want to change each numerical value to its log. In that case, I'd definitely recommend split, eg.

    my($name, @num) = split " "; print $name; for my $num (@num) { print " " . log10($num); } print "\n";
    or
    my($name, @num) = split " "; my @log10; for my $num (@num) { push @log10, log10($num); } print $name, " ", join(" ", @log10), "\n";
Re: Writing file
by Marshall (Canon) on Jun 23, 2011 at 19:57 UTC
    If you want to limit the precision of the log numbers, you can use a format spec in the print statement. %.3f means floating point with 3 decimal places. See below.
    #usr/bin/perl -w use strict; while(<DATA>) { my($name, @num) = split; print $name; foreach my $num (@num) { printf " %.3f", log10($num); } print "\n" } sub log10 { my $n = shift; return log($n)/log(10); } =prints name1 3.171 3.157 3.164 3.160 3.021 3.032 3.036 3.022 name2 3.296 3.290 3.239 3.229 3.286 3.302 3.230 3.266 =cut __DATA__ name1 1481.100 1436.550 1460.410 1444.460 1049.120 1076.890 1085.500 1 +053.100 name2 1978.700 1949.910 1734.030 1694.530 1930.000 2005.530 1696.960 1 +844.810
      thank you very much for your valuable help.