Replacing a “time” column with values in minutes since time "0" [closed] - perl

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I think it won't be a straightforward thing to solve, but here it is. I have a file in the following format:
"2004-04-19 12:25:00" 44 44
"2004-04-19 12:26:30" 36 36
"2004-04-19 12:27:15" 34 34
and I need a file with exact same content, except that the first row of the first column is 0, and remaining values of the first column are times in minutes since time 0 (since first time). Times should be rounded 3 digit after decimal (dot), like this:
0.000 44 44
1.500 36 36
2.250 34 34

I am as disappointed as the others who downvoted your question with your reluctance to even attempt to do this for yourself before asking for free help. If you always do this then you will never learn the language and will always have to rely on other people to do it for you. However, I would prefer that you got your solution from Stack Overflow, as I am sure you will only go elsewhere and ask the same question
This will do as you ask. It expects the path to the input file as a parameter on the command line, and sends the output to STDOUT
To write the output to a file you would redirect it on the command line, like this
$perl fractional_minutes.pl mydata.txt > mydata_new.txt
and if you want to write back to the same file then you will need to use Perl's in-place option, like this
$perl -i.bak fractional_minutes.pl mydata.txt
which will save the old file as mydata.txt.bak
use strict;
use warnings;
use Time::Piece;
use Time::Seconds qw/ ONE_MINUTE /;
my $t0;
while ( <> ) {
s{^"([^"]*)"}{
my $t = Time::Piece->strptime($1, '%Y-%m-%d %H:%M:%S');
$t0 = $t if not defined $t0;
sprintf('%.3f', ($t - $t0) / ONE_MINUTE);
}e;
print;
}
output
0.000 44 44
1.500 36 36
2.250 34 34

With GNU awk for mktime() and gensub():
$ cat tst.awk
BEGIN { FS="\"" }
{ mins=mktime(gensub(/[-:]/," ","g",$2)) / 60 }
NR==1 { startMins=mins }
{ printf "%.3f%s\n", (mins-startMins), $3 }
$ awk -f tst.awk file
0.000 44 44
1.500 36 36
2.250 34 34

Here is a solution that uses Time::Moment:
#!/usr/bin/perl
use strict;
use warnings;
use Time::Moment;
my #times = map {
Time::Moment->from_string($_ . 'Z', lenient => 1)
} ('2004-04-19 12:25:00',
'2004-04-19 12:26:30',
'2004-04-19 12:27:15');
my $first = $times[0];
foreach my $time (#times) {
printf "%.3f\n", ($time->rd - $first->rd) / (1/60/24);
}
Output:
0.000
1.500
2.250

Related

Add "Start of text (Hex 02)" and "End of text (Hex 03)" to a message string using Perl [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 months ago.
Improve this question
Using Perl, I'm trying to add "Start of text (Hex 02)" and "End of text (Hex 03)" to a message string example below:
my $hex02 = 0x02;
my $hex03 = 0x03;
my $hex02_ascii = sprintf "%c", $hex02;
my $hex03_ascii = sprintf "%c", $hex03;
$Message = $hex02_ascii.$Message.$hex03_ascii;
Results are not correct, getting "?datastring?" ?=Hex 3F for Start and End of text...
What I'm trying to achieve is " datastring " (Within double quotes are 0x02,datastring,0x03)
Example:
STX - 1 byte (0x02)
Payload - datastring
ETX - 1 byte (0x03)
What am I doing wrong?
The code you posted does what you want.
$ perl -e'
use v5.14;
use warnings;
my $Message = "datastring";
my $hex02 = 0x02;
my $hex03 = 0x03;
my $hex02_ascii = sprintf "%c", $hex02;
my $hex03_ascii = sprintf "%c", $hex03;
$Message = $hex02_ascii.$Message.$hex03_ascii;
say sprintf "%v02X", $Message;
'
02.64.61.74.61.73.74.72.69.6E.67.03
You could also print out $Message and pipe the output to hexdump -C.
$ perl -e'
...
print $Message;
' | hexdump -C
00000000 02 64 61 74 61 73 74 72 69 6e 67 03 |.datastring.|
0000000c
Without hexdump -C or similar, you can't really tell what output you got because 02 and 03 are not printable characters. Your terminal might display them as ?. But that doesn't mean they are ? (3F).
That said, it can be written a lot simpler.
$Message = "\x02$Message\x03";

Extract blocks of text from a file and write each block to a new file using perl, but it is not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a large data file (text) that contains records from a database.
Each record is is delimited by "-" (146 of them)
I would like to write the text between each delimiter to a new file based on data from that block. The new file name should contain a piece of the data followed be the year (ie 2017)
For instance with this sample file:
1. 12/18/17
Company
PAGE 2
1:14 PM GET CURRENTLY SELECTED DEBTORS
------------------------------------------------------------------------------------------------------------------------
----------------------------- STATUS **Acct:1234** Disposition:9000 CANCEL Wait: 04/11/17
DEBTOR Name:Doe John
Ssn:123456789 Cbr: Ph:555-555-555
Rp:Doe John Ssn: Rp Ph:
Adr1:211 some road POE: Lgl: POE Ph:
City:anytown Cty: Canc:UNC Born:01/01/1937
St: VA Zip:54321 St: Zip: COF:N Sal:
Clnt:00248 Someplace, 93076 Org: 4
80.00
List:01/05/17 Srv:08/25/16 Pl95: Time:9 Calls:0 Con:0 Bal: 480.00
Co-Maker's Previous Address Spouse's Previous Address MULTIPLE
ACCOUNTS RM# Acct Name / Client Chk# / Lst Srv Lpy
Col Disp Bal Check Reason Drivers Licen se #
PRN INT LI3 LI4 AIN CC ATY MS1 PJI 1 142424* Doe John
93076/00248/Somewhere 01/05/17 08/25/16 0 9000
480.00
480.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
2. ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
So from the above is need to extract this block and write it to a new file named 1234_2017.txt based on the Acct:1234 data for that record- then move to the next block. I have counted the number of records for the first file at 754 records, and I have a total of 10 files such as this.
#! / usr/bin/perl -w
use strict;
use warnings;
use POSIX 'strftime';
my $filename = "Facs_Data.txt";
my $outfile = "Acct_".strftime '%Y', localtime;
my $start = "'-' x 146";
open (INFILE, "<$filename"); open (OUTFILE, ">$outfile");
while ($start) {
print $outfile;
next
}
close (INFILE);
close (OUTFILE);
Any suggestions will be greatly appreciated.
If you're not going to put any effort into explaining what you have tried, I'm not going to put any effort into explaining my solution.
#!/usr/bin/perl
use strict;
use warnings;
local $/ = '>' . ('-' x 146) . "\n";
my $year = (localtime)[5] + 1900;
# <> reads from STDIN or a filename given as an argument
while (<>) {
next unless /\S/; # Ignore empty records (like the first one)
my ($acct) = /Acct:(\d+)/;
my $file = "${acct}_${year}.txt";
open my $fh, '>', $file
or die "Can't open $file: $!\n";
print $fh;
}

Perl print changes order of execution

I got a pretty strange problem with my perl-script. I really have no idea, what's happening there, maybe you will see it...
My script uses Net::SSH::Perl to connect to a host-machine via SSH. After that I head -20 on a config.ini and search for some pattern (a version number).
After I print the version number i cat some other file which is approximately 700 lines long.
What's happening now is, that instead of printing the version-number, the script prints the whole 700-line-file. Unless I addprint "\n"x10; directly behind the version-print.
This behaviour doesn't make any sense to me, but I'm sure one of you will be smarter than me and know the answer :)
Below the script:
1 #!/usr/local/bin/perl -w
2 use lib './';
3 use strict;
4
5 use GetVersions;
6 use Net::SSH::Perl;
7
8
9 my $ssh = Net::SSH::Perl->new(
10 'host',
11 identity_files => ['~/.ssh/id_rsa']
12 );
13
14 $ssh->login('user');
15
16 my $ver_regex = '^psadm\.version\s*=\s*rel_(.+)$';
17
18 my ($file, $err, $exit) = $ssh->cmd('head -20 /config.ini');
19 my $version = $file =~ /$ver_regex/m;
20 print "version: $version\n",
21 #print "\n"x10;
22 ($file, $err, $exit) = $ssh->cmd('cat /application.ini');
This should probably be a semicolon
print "version: $version\n",
^

some help on the following perl script

Need help in merging/concatenating /combining /binding etc
I have several ascii files each defining one variable which I have converted to a single column array
I have such columnised data for many variables ,so I need to perform a column bind like R does and make it one single file.
I can do the same in R but there are too many files. Being able to do it with one single code will help save a lot of time.
Using the following code ,new to perl and need help with this.
#filenames = ("file1.txt","file2.txt");
open F2, ">file_combined.txt" or die;
for($j = 0; $j< scalar #filenames;$j++){
open F1, $filenames[$j] or die;
for($i=1;$i<=6;$i++){$line=<F1>;}
while($line=<F1>){
chomp $line;
#spl = split '\s+', $line;
for($i=0;$i<scalar #spl;$i++){
print F2 "$spl[$i]\n";
paste "file_bio1.txt","file_bio2.txt"> file_combined.txt;
}
}
close F1;
}
Input files here are Ascii text files of a raster.They look like this
32 12 34 21 32 21 22 23
12 21 32 43 21 32 21 12
The above mentioned code without the paste syntax converts these files into a single column
32
12
34
21
32
21
22
23
12
21
32
43
21
32
21
12
The output should look like this
12 21 32
32 23 23
32 21 32
12 34 12
43 32 32
32 23 23
32 34 21
21 32 23
Each column represents a different ascii file.
I need around 15 such ascii files into one dataframe.I can do the same in R but it consumes a lot of time as the number of files and regions of interest are too many and the files are a bit large too.
Let's step through what you have...
# files you want to open for reading..
#filenames = ("file1.txt","file2.txt");
# I would use the 3 arg lexical scoped open
# I think you want to open this for 'append' as well
# open($fh, ">>", "file_combined.txt") or die "cannot open";
open F2, ">file_combined.txt" or die;
# #filenames is best thought as a 'list'
# for my $file (#filenames) {
for($j = 0; $j< scalar #filenames;$j++){
# see above example of 'open'
# - $filenames[$j] + $file
open F1, $filenames[$j] or die;
# what are you trying to do here? You're overriding
# $line in the next 'while loop'
for($i=1;$i<=6;$i++){$line=<F1>;}
# while(<$fh1>) {
while($line=<F1>){
chomp $line;
# #spl is short for split?
# give '#spl' list a meaningful name
#spl = split '\s+', $line;
# again, #spl is a list...
# for my $word (#spl) {
for($i=0;$i<scalar #spl;$i++){
# this whole block is a bit confusing.
# 'F2' is 'file_combined.txt'. Then you try and merge
# ( and overwrite the file) with the paste afterwards...
print F2 "$spl[$i]\n";
# is this a 'system call'?
# Missing 'backticks' or 'system'
paste "file_bio1.txt","file_bio2.txt"> file_combined.txt;
}
}
# close $fh1
close F1;
}
# I'm assuming there's a 'close F2' somewhere here..
It looks like you're trying to do this:
#filenames = ("file1.txt","file2.txt");
$oufile = "combined_text.txt";
`paste $filenames[0] $filenames[1] > $outfile`;

Best way to have a formatted output with Perl

I want to output strings into eight columns, but I want to keep the spacing the same. I don't want to do it in HTML, but I am not sure how to do it normally. Example:
Something Something Something Something Something
Else Else Else Else Else
Another Another Another Another Another
The amount of rows will change daily, but the column number will always stay the same. What is the best way to do this?
printf
printf "%-11s %-11s %-11s %-11s %-11s %-11s %-11s %-11s\n",
$column1, $column2, ..., $column8;
Change "11" in the template to whatever value you need.
You could use Perl's format.
This is probably the "complicated" method that you don't understand, most likely because it gives you many options (left|center|right justification/padding, leading 0's, etc).
Perldoc Example:
Example:
format STDOUT =
#<<<<<< #|||||| #>>>>>>
"left", "middle", "right"
.
Output:
left middle right
Here's another tutorial.
Working Example: (Codepad)
#!/usr/bin/perl -w
use strict;
sub main{
my #arr = (['something1','something2','something3','something4','something5','something6','something7','something8']
,['else1' ,'else2' ,'else3' ,'else4' ,'else5' ,'else6' ,'else7' ,'else8' ]
,['another1' ,'another2' ,'another3' ,'another4' ,'another5' ,'another6' ,'another7' ,'another8' ]
);
for my $row (#arr) {
format STDOUT =
#<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<< #<<<<<<<<<<<<
#$row
.
write;
}
}
main();
Here is a live example of Perl6::Form:
#!/usr/bin/perl
use Perl6::Form;
my #arr = (
[1..8],
[9..16],
[17..24],
);
foreach my $line (#arr) {
print form
"{<<<<<} "x8,
#{$line};
}
It will output:
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
I would look at formatting, but I would do it using Perl 6's (now Raku) Form.pm, which you can obtain as Perl6::Form for Perl 5.
The reason for this is that the format builtin has a number of drawbacks, such as having the format statically defined at compile time (i.e., building it dynamically can be painful and usually requires string eval), along with a whole list of other shortcomings, such as lack of useful field types (and you can't extend these in Perl 5).