format output in Perl [duplicate] - perl

I want to output a table containing four variables, an example of the desired format is:
A confusion matrix
H | P |
-----------------------
$var1 | $var2 | H
$var3 | $var4 | P
The problem I am having is that depending on the number of digits in the variables, the format changes and the various lines are offset. I know this is a complete noobie question, but I have never had to pay too much attention to the format of output before, its just one of those little things I want to get right this time. Any help at all would be great, thanks.

Text::Table, Text::SimpleTable::AutoWidth

In addition to daxim's suggestions, there is also Text::TabularDisplay.

You want "format" construct (somewhat inherited from Fortran(!))
http://perldoc.perl.org/functions/format.html

A real example with code with Text::SimpleTable::AutoWidth:
use strict; use warnings;
use Text::SimpleTable::AutoWidth;
print Text::SimpleTable::AutoWidth
->new( max_width => 55, captions => [qw/ Name Age /] )
->row( 'Mother', 59 )
->row( 'Dad', 58 )
->row( 'me', 32 )
->draw();
.--------+-----.
| Name | Age |
+--------+-----+
| Mother | 59 |
| Dad | 58 |
| me | 32 |
'--------+-----'
If you prefer to not install another CPAN module, using format:
#!/usr/bin/env perl
use strict; use warnings;
my ($name, $age, $salary);
format Emp =
#<#<<<<<<<<<#|||||||||||#<#<<#<<#<
'|', $name, '|', $salary, '|', $age, '|'
.
$~ = 'Emp';
# header
print <<EOF;
+----------------+--------+-----+
| Employee name | salary | age |
+----------------+--------+-----+
EOF
my #n = ("Ali", "Raza", "Jaffer");
my #a = (20, 30, 40);
my #s = (2000, 2500, 4000);
my $i = 0;
foreach (#n) {
$name = $_;
$salary = $s[$i];
$age = $a[$i];
write;
}
# footer
print "+-------------------------+-----+\n";
+----------------+--------+-----+
| Employee name | salary | age |
+----------------+--------+-----+
| Ali | 20| 20 |
| Raza | 20| 20 |
| Jaffer | 20| 20 |
+-------------------------+-----+
This syntax is very old and confusing. Up to you.

Related

Perl: Perl6::Form format

I have file something like this,
SR Name Rollno Class
1 Sanjay 01 B
2 Rahul_Kumar_Khanna 09 A
Now I need to add "|" between each. So it should look like
SR | Name |Rollno | Class|
1 | Sanjay |01 | B |
2 | Rahul_Kumar_Khanna|09 | A |
I am using Perl6::form
my $text;
foreach my $line (#arr) {
my ($SR, $Name, $Rollno, $Class) = split (" ", $line);
my $len = length $Name;
$text = form
'| {||||||||} | {||||||||} | {||||||||} | {||||||||}|',
$SR, $Name, $Rollno, $Class;
print $text;
}
Here till now I have done but the name is not comming out properly. I have add extra "|" in name for that. Is there any way we can add "|" by calculating length like(below). I tried but getting error.
'| {||||||||} | {||||||||}x$len | {||||||||} | {||||||||}|',
Problem #1
'| {||||||||} | {||||||||}x$len | {||||||||} | {||||||||}|'
produces
| {||||||||} | {||||||||}x20 | {||||||||} | {||||||||}|
but you're trying to get
| {||||||||} | {||||||||||||||||||||} | {||||||||} | {||||||||}|
For that, you'd want
'| {||||||||} | {'.( "|" x $len ).'} | {||||||||} | {||||||||}|'
Problem #2
$len is the length of the name field of the current row. It's different for every row. This is wrong, cause you want the output to be the same width for every row. $len needs to be the length of the longest name field.
You will need to find the correct value for $len before even starting the loop.
# Read in the data as an array of rows.
# Each row is an array of values.
my #rows = map { [ split ] } <>;
# Find the maximum width of each column.
my #col_lens = (0) x #{rows[0]};
for my $row (#rows) {
# Skip the blank line after the header.
next if !#$row;
for my $col_idx (0..$#$row) {
my $col_len = $row->[$col_idx];
if ($col_lens->[$col_idx] < $col_len) {
$col_lens->[$col_idx] = $col_len;
}
}
}
my $form =
join "",
"| ",
"{".( "|"x($col_lens[0]-2) )."}",
" | ",
"{".( "|"x($col_lens[1]-2) )."}",
" | ",
"{".( "|"x($col_lens[2]-2) )."}",
" | ",
"{".( "|"x($col_lens[3]-2) )."}",
" |";
for my $row (#rows) {
if (#$row) {
print form($form, #$row);
} else {
print "\n";
}
}

Get Multiple IP addresses from one variable using Perl to print a list

I need the script to print out the list of IP addresses line by line with the corresponding username and email address and the country. How do I get the multiple IP addresses to execute a command? I tried doing a loop but it only showed me one line of IP addresses. I would like my output to look like:
1 | login | emailadd#yahoo.com | 160.79.208.82 | United States
16 | login1 | emailadd#yahoo.com | 61.95.83.10 | Italy
23 | login2 | emailadd#gmail.com | 81.48.63.93 | Australia
36 | login3 | emailadd#yahoo.com | 38.117.170.82 | Japan
51 | login4 | emailadd#gmail.com | 2.233.30.85 | Mexico
Here is my code:
#!/usr/bin/perl -w
use lib '~/lib';
use strict;
use Net::IPInfoDB;
my $g = Net::IPInfoDB->new;
$g->key(api_key);
my $login = '1 | login | emailadd#yahoo.com | 160.79.208.82
16 | login1 | emailadd#yahoo.com | 61.95.83.10
23 | login2 | emailadd#gmail.com | 81.48.63.93
36 | login3 | emailadd#yahoo.com | 38.117.170.82
51 | login4 | emailadd#gmail.com | 2.233.30.85';
$login =~ /(\d+\.\d+\.\d+\.\d+)/;
my $city = $g->get_city("$1");
my $addr = $g->get_country("$1");
printf "$login | (%s, %s)\n",
$city->city_name, $addr->country_name;
If you want to stick to not using the array, here's a solution to getting the IP addresses.
while ($login =~ m/(\d+\.\d+\.\d+\.\d+)/g) {
print "$1\n";
}
Use /g to find all matches.
my #ips = /(\d+\.\d+\.\d+\.\d+)/g;
That said, you obviously want the 4th field, so let's actually do that rather than risking getting something from the third field.
sub trim { my ($s) = #_; $s =~ s/^\s+//; $s =~ s/\s+\z//; $s }
for (split /^/m, $login) {
chomp;
my #fields = map trim($_), split /\|/;
my $ip = $fields[2];
...
}
You are getting only one IP address, because it is exactly what you are doing by applying the regex ONCE on the whole $login.
#we split $login into an array, line-by-line
my #lines = split("\n",$login);
for my $line (#lines) {
#now we iterate through every line one-by-one
$line =~ /(?<ip>\d+\.\d+\.\d+\.\d+)/;
print $+{"ip"}."\n";
}
Here we iterated through every line on $login and we applied the regex for each line individually..Instead of printing ofc you can do whatever you want with that ip.
Also I'm using here named match, which is only my preference, you don't have to use it.

Perl create a formatted table without using an object

I want to simply output some results in a table without there being any offset problems. Do not worry about the foreach and the output of values that is just pseudocode for clarity.
print "\n ______________________________________________________";
print "\n | |";
print "\n | Title |";
print "\n +______________________________________________________+";
print "\n | | |";
print "\n | City | Size |";
print "\n |__________________________|___________________________|";
#Sort by highest scores
################################
foreach (city, size)
{
print "\n | (city(value)";
print "| (size(value)";
}
Any Ideas?
It's rarely used anymore, but Perl has the built in ability to create these type of forms.
Basically, you use a specification to state how you want these tables formatted, and where information in these tables will be placed using the format statement. Then, you use the Perl write statement to write to that format. You can specify headers and footers of your tables too.
I suggest you use
substr
to overwrite the correct portion of a template line.
use strict;
use warnings;
my %data = (
Birmingham => 1_000_000,
Bristol => 430_000,
Manchester => 110_000,
);
print " ______________________________________________________\n";
print " | |\n";
print " | Title |\n";
print " +______________________________________________________+\n";
my $template =
" | | |\n";
print $template;
while (my ($city, $size) = each %data) {
my $line = $template;
substr $line, 12, length $city, $city;
substr $line, 39, length $size, $size;
print $line;
}
print " |__________________________|___________________________|\n";
output
______________________________________________________
| |
| Title |
+______________________________________________________+
| | |
| Bristol | 430000 |
| Manchester | 110000 |
| Birmingham | 1000000 |
|__________________________|___________________________|

Working with Spreadsheet::ParseExcel

I am working with an Excel worksheet to fetch two columns and replace file names based on them.
This is how I get the values of two columns that I am interested in. the 14th column could be a single value or more than one separated by a comma.
my #required = (2,14);
my #value;
my #files = grep{ -f && -T && -M > 0 } glob("$dir/*");
my #expected_file = grep{ /Parsed/ } #files;
print "#expected_file\n";
if(! $workbook) {
die $parser->error(),"\n";
}
for my $row (1 .. $row_max) {
#value = map{
my $cell = $worksheets[0]->get_cell($row,$_);
$cell ? $cell->value() : '';
}#required;
my %hash_value = #value;
foreach my $key (keys %hash_value ){
my #suffix = split /[, ]/,$hash_value{$key};
push #{ $resample->{$key} },#suffix;
print $key . ":" .#suffix,"\n";
}
}
Output would be :
TY45745a:A,BTY45745a:C,DTY45745a:E,FTY5475a:G,HTY5475a:I,JTY5475a:K,L
Where TY45745a,TY5475a are the keys.What I would like to achieve is something like this : TY45745a A,B,C,D,E,F and TY5475a G,H,I,J,K,L.
And if the file names has [A-E] at the end of the file then it should be renamed to TY45745a[1..6], and if it has [G-L] TY5475a[1..6].
Could this grouping of suffix for a name could be done when fetching from the Excel sheet?
How should I do this ? Any suggestions or pointers will be helpful .
I assume that your table looks like:
| B (2) | N (14) |
|:--------:|:-------:|
| TY45745a | A,B |
| TY45745a | C,D |
| TY45745a | E,F |
| TY5475a | G,H |
| TY5475a | I,J |
| TY5475a | K,L |
You can do the first part
Where TY45745a,TY5475a are the keys.What I would like to achieve is something like this : TY45745a A,B,C,D,E,F and TY5475a G,H,I,J,K,L.
with the following code:
use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Data::Dumper;
my $parser = Spreadsheet::ParseExcel->new();
my $book = $parser->Parse('Mappe1.xls') or die $parser->error(),"\n";
my $sheet = $book->{Worksheet};
my %hash;
for my $row (0 .. $sheet->[0]{MaxRow}) {
my $c2 = $sheet->[0]->get_cell($row, 2-1);
my $key = $c2 ? $c2->value() : '';
my $c14 = $sheet->[0]->get_cell($row, 14-1);
my #values = $c14 ? split(',', $c14->value()) : ();
push #{$hash{$key}}, #values;
}
print Dumper \%hash;
I added the missing parts to get the code running and simplified it a little
bit for demonstration purposes.

How do I output a text table in Perl?

I want to output a table containing four variables, an example of the desired format is:
A confusion matrix
H | P |
-----------------------
$var1 | $var2 | H
$var3 | $var4 | P
The problem I am having is that depending on the number of digits in the variables, the format changes and the various lines are offset. I know this is a complete noobie question, but I have never had to pay too much attention to the format of output before, its just one of those little things I want to get right this time. Any help at all would be great, thanks.
Text::Table, Text::SimpleTable::AutoWidth
In addition to daxim's suggestions, there is also Text::TabularDisplay.
You want "format" construct (somewhat inherited from Fortran(!))
http://perldoc.perl.org/functions/format.html
A real example with code with Text::SimpleTable::AutoWidth:
use strict; use warnings;
use Text::SimpleTable::AutoWidth;
print Text::SimpleTable::AutoWidth
->new( max_width => 55, captions => [qw/ Name Age /] )
->row( 'Mother', 59 )
->row( 'Dad', 58 )
->row( 'me', 32 )
->draw();
.--------+-----.
| Name | Age |
+--------+-----+
| Mother | 59 |
| Dad | 58 |
| me | 32 |
'--------+-----'
If you prefer to not install another CPAN module, using format:
#!/usr/bin/env perl
use strict; use warnings;
my ($name, $age, $salary);
format Emp =
#<#<<<<<<<<<#|||||||||||#<#<<#<<#<
'|', $name, '|', $salary, '|', $age, '|'
.
$~ = 'Emp';
# header
print <<EOF;
+----------------+--------+-----+
| Employee name | salary | age |
+----------------+--------+-----+
EOF
my #n = ("Ali", "Raza", "Jaffer");
my #a = (20, 30, 40);
my #s = (2000, 2500, 4000);
my $i = 0;
foreach (#n) {
$name = $_;
$salary = $s[$i];
$age = $a[$i];
write;
}
# footer
print "+-------------------------+-----+\n";
+----------------+--------+-----+
| Employee name | salary | age |
+----------------+--------+-----+
| Ali | 20| 20 |
| Raza | 20| 20 |
| Jaffer | 20| 20 |
+-------------------------+-----+
This syntax is very old and confusing. Up to you.