ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I want to modify this file so that all numbers from position 3 until end of line (28..31 numbers, ie days of month) are multiplied by a factor 9.5, so that the output looks like the below. Note that some days might lack a value. In that case output shall be 0.
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'test.txt';
my $outfile = 'test-out.txt';
open (my $fh, $file) or die "Could not open file, '$file' $!";
open (my $wfh, '>', $outfile) or die "Could not open file, '$outfile' $!";
while (my $row = <$fh>) {
my @values = split(';', $row );
for (my $i=2; $i<8; $i++) {
if ( $values[$i] eq '' ){
$values[$i] = 0;
}
$values[$i] = $values[$i] * 9.5;
}
for (my $i=0; $i<8; $i++) {
printf $wfh "$values[$i] ; ";
}
printf $wfh "$values[8]";
}
close $fh;
close $wfh;
My first reply would have been "What have you tried? And what avenue (or language) did you wish to pursue to solve this? Along with what is your expertise with scripting languages or other?"
But it appears that a proposed solution has been posted.
Please try that out and update your fellow forum members if you feel that solved your problem, or if you have further questions.
Thanks for the replies.
The reason I didn't say anything about what I've tried here, is that I didn't know how to approach this problem.
I'm a little bit familiar with awk and sed, and that would have been my avenue to pursue to solve this, if it would have been do-able.
But perl will work as well, so thanks a lot for the perl suggestion.
I did try it out, and found a few things I would like to comment:
1) I replaced the value 8 in the script with a higher value (38), since the number of words on each line is "2 + the number of days in month", ie. between 30 and 33 numbers in total per line. Is it ok with a high number like 38, that is higher than the exact number of words in the line?
2) An empty value (ie only space between to semicolons) seems not to be acceptable? Got error:
Argument " " isn't numeric in multiplication (*) at ./script.pl line 14, <$fh> line 3.
(I think I can find ways to get around this error, e.g. by search and replace "; ;" with ";0;".
3) The output test-out.txt seems to all come on 1 line? How can I get the output on 3 lines (as in the input file)? I have of course more than 3 lines, but you get the idea...
#!/usr/bin/env perl
use strict;
use warnings;
use constant FILE => 'file.csv';
my @rows;
open my $fh, '<', FILE or die $!;
while (my $row = <$fh>) {
my @columns = split(/\s?;\s?/, $row);
my @values = map { /^[0-9]+$/ ? ($_ or 0) * 9.5 : $_ } splice(@columns, 2);
unshift @values, $columns[1];
unshift @values, $columns[0];
push @rows, join(';', @values);
}
close $fh;
open $fh, '>', FILE or die $!;
for my $row (@rows) {
print $fh "$row\n";
}
close $fh;
EDIT: You can also get fancy and modify the row in-place. This version was just for my amusement, but you can still use it for your purpose.
Code:
#!/usr/bin/env perl
use strict;
use warnings;
use constant FILE => 'file.csv';
my @rows;
open my $fh, '<', FILE or die $!;
while (my $row = <$fh>) {
my @columns = split(/\s?;\s?/, $row);
@columns[2 .. $#columns] = map { /^[0-9]+$/ ? ($_ or 0) * 9.5 : $_ } @columns[2 .. $#columns];
push @rows, join(' ; ', @columns);
}
close $fh;
open $fh, '>', FILE or die $!;
for my $row (@rows) {
print $fh "$row\n";
}
close $fh;
Last edited by individual; 10-16-2018 at 05:31 PM.
Reason: Removed unnecessary string concatenation.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.