Sum of hex values in perl - perl

I am trying to input 2 ascii files and output them into 2 hex files (sym.txt ,sym2.txt) and then do the sum of two hex files and output the reverse of the value into a last file (symout.txt).I really don't see what I'm doing wrong ... Thank you for the help in advance :D.
use strict;
use warnings 'all';
open my $in, "<", "f1.txt";
my $input = do { local $/; <$in> };
open my $out, ">", "sym.txt";
print $out unpack 'H*', $input;
open my $in1, "<", "f2.txt";
my $input1 = do { local $/; <$in1> };
open my $out1, ">", "sym2.txt";
print $out1 unpack 'H*', $input1;
open(my $fh1, '<', 'sym.txt') or die $!;
open(my $fh2, '<', 'sym2.txt') or die $!;
open my $fh_out, '>', 'symout.txt' or die $!;
until ( eof $fh1 or eof $fh2 ) {
my #l1 = map hex, split '', <$fh1>;
my #l2 = map hex, split '', <$fh2>;
my $n = #l2 > #l1 ? #l2 : #l1;
my #sum = map {
no warnings 'uninitialized';
$l1[$_] + $l2[$_];
} 0 .. $n-1;
#sum = map { sprintf '%X', $_ } #sum;
print { $fh_out } reverse(#sum), "\n";
}

The main problem is that you haven't closed $out or $out1, so the data that has been printed to those handles is still in memory waiting to be flushed
It's best to use lexical file handles (as you are doing) and add blocks so that the handles are closed implicitly when they go out of scope
Here's an example of what I mean. Note that I've also added use autodie to avoid having to check the status of every open call (which you should have done but didn't!)
use strict;
use warnings 'all';
use v5.14;
use autodie;
{
my $input = do {
open my $in, '<', 'f1.txt';
local $/;
<$in>
};
open my $out, '>', 'sym.txt';
print $out unpack 'H*', $input;
}
{
my $input = do {
open my $in, '<', 'f2.txt';
local $/;
<$in>
};
open my $out, '>', 'sym2.txt';
print $out unpack 'H*', $input;
}
open my $fh1, '<', 'sym.txt';
open my $fh2, '<', 'sym2.txt';
until ( eof $fh1 or eof $fh2 ) {
my #l1 = map hex, split //, <$fh1>;
my #l2 = map hex, split //, <$fh2>;
my $n = #l2 > #l1 ? #l2 : #l1;
my #sum = map {
no warnings 'uninitialized';
$l1[$_] + $l2[$_];
} 0 .. $n-1;
#sum = map { sprintf '%X', $_ } #sum;
open my $out, '>', 'symout.txt';
print { $out } reverse(#sum), "\n";
}

Related

Duplicate values in column

I have a original file which has following columns,
02-May-2018,AAPL,Sell,0.25,1000
02-May-2018,C,Sell,0.25,2000
02-May-2018,JPM,Sell,0.25,3000
02-May-2018,WFC,Sell,0.25,5000
02-May-2018,AAPL,Sell,0.25,7000
02-May-2018,GOOG,Sell,0.25,8000
02-May-2018,GOOG,Sell,0.25,9000
02-May-2018,C,Sell,0.25,2000
02-May-2018,AAPL,Sell,0.25,3000
I am trying to print this original line if I see value in the second column more then 2 times.. for example, if I see AAPL more then 2 times desired result should print
02-May-2018,AAPL,Sell,0.25,1000
02-May-2018,AAPL,Sell,0.25,7000
02-May-2018,AAPL,Sell,0.25,3000
So Far, I have written the following which prints results multiple times which is wrong.. can you please help on what I am doing wrong?
open (FILE, "<$TMPFILE") or die "Could not open $TMPFILE";
open (OUT, ">$TMPFILE1") or die "Could not open $TMPFILE1";
%count = ();
#symbol = ();
while ($line = <FILE>)
{
chomp $line;
(#data) = split(/,/,$line);
$count{$data[1]}++;
#keys = sort {$count{$a} cmp $count{$b}} keys %count;
for my $key (#keys)
{
if ( $count{$key} > 2 )
{
print "$line\n";
}
}
}
I'd do it something like this - store lines you've seen in a 'buffer' and print them out again if the condition is hit (before continuing to print as you go):
#!/usr/bin/env perl
use strict;
use warnings;
my %buffer;
my %count_of;
while ( my $line = <> ) {
my ( $date, $ticker, #values ) = split /,/, $line;
#increment the count
$count_of{$ticker}++;
if ( $count_of{$ticker} < 3 ) {
#count limit not hit, so stash the current line in the buffer.
$buffer{$ticker} .= $line;
next;
}
#print the buffer if the count has been hit
if ( $count_of{$ticker} == 3 ) {
print $buffer{$ticker};
}
#only gets to here once the limit is hit, so just print normally.
print $line;
}
With your input data, this outputs:
02-May-2018,AAPL,Sell,0.25,1000
02-May-2018,AAPL,Sell,0.25,7000
02-May-2018,AAPL,Sell,0.25,3000
Simple answer:
push #{ $lines{(split",")[1]} }, $_ while <>;
print #{ $lines{$_} } for grep #{ $lines{$_} } > 2, sort keys %lines;
perl program.pl inputfile > outputfile
You need to read the input file twice, because you don't know the final counts until you get to the end of the file
use strict;
use warnings 'all';
my ($TMPFILE, $TMPFILE1) = qw/ infile outfile /;
my %counts;
{
open my $fh, '<', $TMPFILE or die "Could not open $TMPFILE: $!";
while ( <$fh> ) {
my #fields = split /,/;
++$counts{$fields[1]};
}
}
open my $fh, '<', $TMPFILE or die "Could not open $TMPFILE: $!";
open my $out_fh, '>', $TMPFILE1 or die "Could not open $TMPFILE1: $!";
while ( <$fh> ) {
my #fields = split /,/;
print $out_fh $_ if $counts{$fields[1]} > 2;
}
output
02-May-2018,AAPL,Sell,0.25,1000
02-May-2018,AAPL,Sell,0.25,7000
02-May-2018,AAPL,Sell,0.25,3000
This should work:
use strict;
use warnings;
open (FILE, "<$TMPFILE") or die "Could not open $TMPFILE";
open (OUT, ">$TMPFILE1") or die "Could not open $TMPFILE1";
my %data;
while ( my $line = <FILE> ) {
chomp $line;
my #line = split /,/, $line;
push(#{$data{$line[1]}}, $line);
}
foreach my $key (keys %data) {
if(#{$data{$key}} > 2) {
print "$_\n" foreach #{$data{$key}};
}
}

Find and replace a string in a text file in Perl

I really have no idea how to do this. I tried a lot methods and I don't know why none works. Here is a sample of what I tried:
{
open my $fh1, '<', 'hex1.txt';
open my $fh2, '<', 'hex2.txt';
until ( eof $fh1 or eof $fh2 ) {
my #l1 = map hex, split //, <$fh1>;
my #l2 = map hex, split //, <$fh2>;
my $n = #l2 > #l1 ? #l2 : #l1;
my #sum = map {
no warnings 'uninitialized';
$l1[$_] + $l2[$_];
} 0 .. $n - 1;
#sum = map { sprintf '%X', $_ } #sum;
open my $out, '>', 'hexsum.txt';
print {$out} #sum, "\n";
}
close $fh1;
close $fh2;
}
{
open my $IN, "<", 'hexsum.txt';
open my $OUT, ">", 'sym.txt';
while ( my $linie = <$IN> ) {
$linie =~ s/40/20/g;
print $OUT $linie;
}
close $IN;
close $OUT;
}
{
my $input = do {
open my $in, '<', 'hexsumspace.txt';
local $/;
<$in>;
};
open my $out, '>', 'sym.txt';
print $out pack 'H*', $input;
}
How can I change it everywhere I find the value 40 with the value 20?
use strict;
use warnings;
open my $OUT, ">", 'output.txt';
open my $IN, "<", 'input.txt';
while (my $line = <$IN>) {
$line =~ s/40/20/g;
print $OUT $line;
}
close $IN;
close $OUT;
Here's a Perl one-liner from the command line:
perl -pe 's/40/20/g' input.txt > output.txt

perl script only write one row to output file in perl

i wrote a script to open a file on web, and pull out all rows with wireless in the name. It writes the out put to a different file, but it only records one line in the output file, should be mulitipe lines.
#!\Perl64\eg\perl -w
use warnings;
use strict;
use LWP::Simple;
my $save = "C:\\wireless\\";
my $file = get 'http://dhcp_server.test.com/cgi-bin/dhcp_utilization_csv_region.pl?region=test';
open( FILE, '>', $save . 'DHCP_Utilization_test.csv' ) or die $!;
binmode FILE;
print FILE $file;
close(FILE);
open( F, "C:\\wireless\\DHCP_Utilization_test.csv" ) || die "can't opern file: $!";
my #file = <F>;
close(F);
my $line;
foreach $line (#file) {
chomp $line;
if ( $line =~ m/Wireless /g ) {
my ($ip, $rtr, $mask, $zip, $blc, $address, $city,
$state, $space, $country, $space2, $noc, $company, $extra,
$active, $used, $percent, $extra3, $nus, $construct
) = split( /,/, $line );
my $custom_directory = "C:\\wireless\\";
my $custom_filename = "wireless_DHCP.csv";
my $data = "$ip $mask $rtr $active $used $percent $nus $construct";
my $path = "$custom_directory\\$custom_filename";
open( my $handle, ">>", $path ) || die "can't open $path: $!";
binmode($handle); # for raw; else set the encoding
print $handle "$data\n";
close($handle) || die "can't close $path: $!";
}
}
I believe the problem is because you're on Windows, but then saving the file using :raw, and then reopening it using :crlf.
open( FILE, '>', $save . 'DHCP_Utilization_test.csv' ) or die $!;
binmode FILE;
print FILE $file;
close(FILE);
open( F, "C:\\wireless\\DHCP_Utilization_test.csv" ) || die "can't opern file: $!";
my #file = <F>;
close(F);
I therefore suspect that your #file array only contains one line for the entire file.
You can probably also tighten your code to something like the following:
#!\Perl64\eg\perl
use strict;
use warnings;
use autodie;
use LWP::Simple;
my $url = 'http://dhcp_server.test.com/cgi-bin/dhcp_utilization_csv_region.pl?region=test';
my $datafile = "C:\\wireless\\DHCP_Utilization_test.csv";
my $wireless = "C:\\wireless\\wireless_DHCP.csv";
getstore( $url, $datafile );
open my $infh, '<', $datafile;
open my $outfh, '>>', $wireless;
while (<$infh>) {
chomp;
next unless /Wireless /;
my ($ip, $rtr, $mask, $zip, $blc, $address, $city,
$state, $space, $country, $space2, $noc, $company, $extra,
$active, $used, $percent, $extra3, $nus, $construct
) = split /,/;
print $outfh "$ip $mask $rtr $active $used $percent $nus $construct\n";
}

How can I print lines from a file to separate files

I have a file which has lines like this:
1 107275 447049 scaffold1443 465 341154 -
There are several lines which starts with one, after that a blank line separates and start lines with 2 and so on.
I want to separate these lines to different files based on their number.
I wrote this script but it prints in every file only the first line.
#!/usr/bin/perl
#script for choosing chromosome
use strict;
my $filename= $ARGV[0];
open(FILE, $filename);
while (my $line = <FILE>) {
my #data = split('\t', $line);
my $length = #data;
#print $length;
my $num = $data[0];
if ($length == 6) {
open(my $fh, '>', $num);
print $fh $line;
}
$num = $num + 1;
}
please, i need your help!
use >> to open file for appending to end of it as > always truncates desired file to zero bytes,
use strict;
my $filename = $ARGV[0];
open(my $FILE, "<", $filename) or die $!;
while (my $line = <$FILE>) {
my #data = split('\t', $line);
my $length = #data;
#print $length;
my $num = $data[0];
if ($length == 6) {
open(my $fh, '>>', $num);
print $fh $line;
}
$num = $num + 1;
}
If I understand your question correctly, then paragraph mode might be useful. This breaks a record on two or more new-lines, instead of just one:
#ARGV or die "Supply a filename\n";
my $filename= $ARGV[0];
local $/ = ""; # Set paragraph mode
open(my $file, $filename) or die "Unable to open '$filename' for read: $!";
while (my $lines = <$file>) {
my $num = (split("\t", $lines))[0];
open(my $fh, '>', $num) or die "Unable to open '$num' for write: $!";
print $fh $lines;
close $fh;
}
close $file;

Extracting specific multiple line of records that is pipe delimited in perl

I have a file that looks like
NAME|JOHN|TOKYO|JPN
AGE|32|M
INFO|SINGLE|PROFESSIONAL|IT
NAME|MARK|MANILA|PH
AGE|37|M
INFO|MARRIED|PROFESSIONAL|BPO
NAME|SAMANTHA|SYDNEY|AUS
AGE|37|F
INFO|MARRIED|PROFESSIONAL|OFFSHORE
NAME|LUKE|TOKYO|JPN
AGE|27|M
INFO|SINGLE|PROFESSIONAL|IT
I want to separate the records by country. I have stored each line into array variable #fields
my #fields = split(/\|/, $_ );
making $fields[3] as my basis for sorting it. I wanted it to separate into 2 output text files
OUTPUT TEXT FILE 1:
NAME|JOHN|TOKYO|JPN
AGE|32|M
INFO|SINGLE|PROFESSIONAL|IT
NAME|LUKE|TOKYO|JPN
AGE|27|M
INFO|SINGLE|PROFESSIONAL|IT
OUTPUT TEXT FILE 2
NAME|MARK|MANILA|PH
AGE|37|M
INFO|MARRIED|PROFESSIONAL|BPO
NAME|SAMANTHA|SYDNEY|AUS
AGE|37|F
INFO|MARRIED|PROFESSIONAL|OFFSHORE
Putting all that is from JPN to output text 1 & non-JPN country to output text file 2
here's the code that what trying to work out
use strict;
use warnings;
use Data::Dumper;
use Carp qw(croak);
my #fields;
my $tmp_var;
my $count;
;
my ($line, $i);
my $filename = 'data.txt';
open(my $input_fh, '<', $filename ) or croak "Can't open $filename: $!";
open(OUTPUTA, ">", 'JPN.txt') or die "wsl_reformat.pl: could not open $ARGV[0]";
open(OUTPUTB, ">", 'Non-JPN.txt') or die "wsl_reformat.pl: could not open $ARGV[0]";
my $fh;
while (<$input_fh>) {
chomp;
my #fields = split /\|/;
if ($fields[0] eq 'NAME') {
for ($i=1; $i < #fields; $i++) {
if ($fields[3] eq 'JPN') {
$fh = $_;
print OUTPUTA $fh;
}
else {
$fh = $_;
print OUTPUTB $fh;
}
}
}
}
close(OUTPUTA);
close(OUTPUTB)
Still has no luck on it :(
Here is the way I think ikegami was saying, but I've never tried this before (although it gave the correct results).
#!/usr/bin/perl
use strict;
use warnings;
open my $jpn_fh, ">", 'o33.txt' or die $!;
open my $other_fh, ">", 'o44.txt' or die $!;
my $fh;
while (<DATA>) {
if (/^NAME/) {
if (/JPN$/) {
$fh = $jpn_fh;
}
else {
$fh = $other_fh;
}
}
print $fh $_;
}
close $jpn_fh or die $!;
close $other_fh or die $!;
__DATA__
NAME|JOHN|TOKYO|JPN
AGE|32|M
INFO|SINGLE|PROFESSIONAL|IT
NAME|MARK|MANILA|PH
AGE|37|M
INFO|MARRIED|PROFESSIONAL|BPO
NAME|SAMANTHA|SYDNEY|AUS
AGE|37|F
INFO|MARRIED|PROFESSIONAL|OFFSHORE
NAME|LUKE|TOKYO|JPN
AGE|27|M
INFO|SINGLE|PROFESSIONAL|IT
You didn't say what you needed help with, so I'm assuming it's coming up with an algorithm. Here's a good one:
Open the file to read.
Open the file for the JPN entries.
Open the file for the non-JPN entries.
While not eof,
Read a line.
Parse the line.
If it's the first line of a record,
If the person's country is JPN,
Set current file handle to the file handle for JPN entries.
Else,
Set current file handle to the file handle for non-JPN entries.
Print the line to the current file handle.
my $jpn_qfn = '...';
my $other_qfn = '...';
open(my $jpn_fh, '>', $jpn_qfn)
or die("Can't create $jpn_qfn: $!\n");
open(my $other_fh, '>', $other_qfn)
or die("Can't create $other_qfn: $!\n");
my $fh;
while (<>) {
chomp;
my #fields = split /\|/;
if ($fields[0] eq 'NAME') {
$fh = $fields[3] eq 'JPN' ? $jpn_fh : $other_fh;
}
say $fh $_;
}
#!/usr/bin/env perl
use 5.012;
use autodie;
use strict;
use warnings;
# store per country output filehandles
my %output;
# since this is just an example, read from __DATA__ section
while (my $line = <DATA>) {
# split the fields
my #cells = split /[|]/, $line;
# if first field is NAME, this is a new record
if ($cells[0] eq 'NAME') {
# get the country code, strip trailing whitespace
(my $country = $cells[3]) =~ s/\s+\z//;
# if we haven't created and output file for this
# country, yet, do so
unless (defined $output{$country}) {
open my $fh, '>', "$country.out";
$output{$country} = $fh;
}
my $out = $output{$country};
# output this and the next two lines to
# country specific output file
print $out $line, scalar <DATA>, scalar <DATA>;
}
}
close $_ for values %output;
__DATA__
NAME|JOHN|TOKYO|JPN
AGE|32|M
INFO|SINGLE|PROFESSIONAL|IT
NAME|MARK|MANILA|PH
AGE|37|M
INFO|MARRIED|PROFESSIONAL|BPO
NAME|SAMANTHA|SYDNEY|AUS
AGE|37|F
INFO|MARRIED|PROFESSIONAL|OFFSHORE
NAME|LUKE|TOKYO|JPN
AGE|27|M
INFO|SINGLE|PROFESSIONAL|IT
Thanks for your Help heaps
I was able to solved this problem in perl,
many thanks
#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Carp qw(croak);
my #fields;
my $tmp_var;
my ($rec_type, $country);
my $filename = 'data.txt';
open (my $input_fh, '<', $filename ) or croak "Can't open $filename: $!";
open my $OUTPUTA, ">", 'o33.txt' or die $!;
open my $OUTPUTB, ">", 'o44.txt' or die $!;
my $Combline;
while (<$input_fh>) {
$_ = _trim($_);
#fields = split (/\|/, $_);
$rec_type = $fields[0];
$country = $fields[3];
if ($rec_type eq 'NAME') {
if ($country eq 'JPN') {
*Combline = $OUTPUTA;
}
else {
*Combline = $OUTPUTB;
}
}
print Combline;
}
close $OUTPUTA or die $!;
close $OUTPUTB or die $!;
sub _trim {
my $word = shift;
if ( $word ) {
$word =~ s/\s*\|/\|/g; #remove trailing spaces
$word =~ s/"//g; #remove double quotes
}
return $word;
}