3 Replies - 6446 Views - Last Post: 24 November 2010 - 02:18 AM

#1 lucky04  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 18-September 07

perl/cgi: populating a table in html, from a regex

Posted 22 November 2010 - 08:40 PM

I have the "uptime" completed, and a start to the "users", but i cannot figure out how to fully populate the html table from the perl regex. I was able to manually get the first row in as you can see, but cant figure out how to do a loop that would properly fulfill the table.


#!/usr/bin/perl

use warnings;
use strict;
use CGI qw/:standard/;
use CGI::Carp qw/fatalsToBrowser/;

my $finger = `finger`;
my $uptime = `uptime`;
print header();

print start_html( -title=>'A Sample CGI-Generated Page');
print h1("Blizzard Stats");
print br;
print h3("Uptime");
$uptime =~ /(\d+:\d+:\d+)\s+(\S+)\s+(\d+)\s+(\S+),\s+(\d+)(:)/>(\d+),\s+(\d+\s+users),\s+(load average:)\s+(\d.\d+),\s+(\d.\d+),\s+(\d.\d+)/g;
print table
	(
		{-border=>undef, width=>"50%"},
		Tr ( td("Current Date:"), td($1)),
		Tr ( td("Uptime"), td($3." ".$4.", ".$5." hours, ".$7." minutes")),
		Tr ( td("1 min. Load Average"), td($10." jobs")),
		Tr ( td("5 min. Load Average"), td($11." jobs")),
		Tr ( td("15 min. Load Average"), td($12." jobs"))
	);

print h3("Users");
print $finger;

print br;
print br;
my $header = $finger;
$header =~ m/^.*Phone/;

$finger =~ s/^.*Phone//;
$finger =~ /(\S+)\s+(\S+\s+\S+)\s+(pts\/\d+)\s+(\S+\s+\d+)\s+(\d+:\d+)\s+(\(.*\))/g;

print table
	(
		{-border=>undef, width=>"50%"},
		Tr ( td("Username"), td("Full Name"), td("Idle Time"), td("Computer")),
		Tr ( td($1), td($2), td($5), td($6))
	);

print br;

print end_html();




attached is a screenshot of my results

Attached image(s)

  • Attached Image


Is This A Good Question/Topic? 0
  • +

Replies To: perl/cgi: populating a table in html, from a regex

#2 dsherohman  Icon User is offline

  • Perl Parson
  • member icon

Reputation: 227
  • View blog
  • Posts: 654
  • Joined: 29-March 09

Re: perl/cgi: populating a table in html, from a regex

Posted 23 November 2010 - 05:16 AM

Truth be told, a regex really isn't the best choice for parsing fixed-width fields that don't have delimiters separating them. It's a particular problem in this case because the field data contains whitespace, so you won't get the right results by just splitting on whitespace.

No, you need to use unpack here instead[1]:
#!/usr/bin/env perl

use strict;
use warnings;

use CGI qw/:standard/;

my $finger = <<'FINGER';
Login     Name             Tty      Idle  Login Time   Office     Office Phone
dave      Dave Sherohman  *pts/0          Nov 23 01:59 (somewhere.on.the.net)
FINGER

my @finger_lines = split '\n', $finger;
my @user_table_body;

# First line of finger output is the field names, so ignore it
shift @finger_lines;
$user_table_body[0] =
  Tr(th('Login'), th('Name'), th('Tty'), th('Idle'), th('Login Time'));

for my $line (@finger_lines) {
    my @user = parse_finger_line($line);
    push @user_table_body, Tr(map { td($_) } @user);
}

print table({-border => undef, width => "50%"}, @user_table_body);

sub parse_finger_line {
    my $line = shift;
    return unpack 'A10 A16 A10 A6 A*', $line;
}



I've never actually used CGI.pm's HTML-generating functions[2], so it may be possible to clean that up a bit more, but examining the output of this program shows that it creates the correct HTML table markup for the hardcoded input, so it appears to be correct, even if not optimal.

Your finger may vary. If it uses different field widths than mine, you can easily tweak the unpack template to adjust for it - A10 is 10 ASCII characters, A16 is 16 characters, etc. If you really wanted to be fancy, you could use the index function to find the position of each heading in the first line of finger output and build a dynamic unpack format based on that. While this would be fun to play with, I leave it as an exercise for the reader.


[1] Well, OK, you can force regexes to handle fixed width data by doing something like m/^(.{10})(.{16})(.{10})(.{6})(.*)/, but unpack is cleaner and more efficient, plus the regex leaves you still needing to trim trailing whitespace for yourself, while unpack does that for you automatically.

[2] If you start building web apps of any scale, you'll want to use a templating system, such as Template::Toolkit ( http://search.cpan.o...mplate::Toolkit ) to build your output pages.
Was This Post Helpful? 1
  • +
  • -

#3 lucky04  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 18-September 07

Re: perl/cgi: populating a table in html, from a regex

Posted 23 November 2010 - 08:19 AM

Thanks for the advice up there, I implemented it, and got ALOT closer. Still having troubles getting the fields right and i played with it for a good couple hours. Yes i'm an idiot :)

#!/usr/bin/perl


use warnings;
use strict;
use CGI qw/:standard/;
use CGI::Carp qw/fatalsToBrowser/;

my $finger = `finger`;
my $uptime = `uptime`;
print header();

print start_html( -title=>'A Sample CGI-Generated Page');
print h1("Blizzard Stats");
print br;
print h3("Uptime");
$uptime =~ /(\d+:\d+:\d+)\s+(\S+)\s+(\d+)\s+(\S+),\s+(\d+)(:)/>(\d+),\s+(\d+\s+users),\s+(load average:)\s+(\d.\d+),\s+(\d.\d+),\s+(\d.\d+)/g;
print table
	(
		{-border=>undef, width=>"50%"},
		Tr ( td("Current Date:"), td($1)),
		Tr ( td("Uptime"), td($3." ".$4.", ".$5." hours, ".$7." minutes")),
		Tr ( td("1 min. Load Average"), td($10." jobs")),
		Tr ( td("5 min. Load Average"), td($11." jobs")),
		Tr ( td("15 min. Load Average"), td($12." jobs"))
	);



print h3("Users");
 
my @finger_lines = split '\n', $finger;
my @user_table_body;
 
# First line of finger output is the field names, so ignore it
shift @finger_lines;
$user_table_body[0] = Tr(th('Login'), th('Full Name'), th('Idle Time'), th('Computer'));
 
foreach my $line (@finger_lines) 
{
    my @user = parse_finger_line($line);
    push @user_table_body, Tr(map { td($_) } @user);
}
 
print table({-border => undef, width => "50%"}, @user_table_body);
 
sub parse_finger_line 
{
    my $line = shift;
    return unpack 'A10 A16 A4 A16', $line;
}
print br;

print end_html();



see the attachment below. THe fields should match up like the attached picture in post 1. I tried all different combinations of the unpack 'A.........", and tried switching things up higher. THoughts anyone?

Attached image(s)

  • Attached Image

Was This Post Helpful? 0
  • +
  • -

#4 dsherohman  Icon User is offline

  • Perl Parson
  • member icon

Reputation: 227
  • View blog
  • Posts: 654
  • Joined: 29-March 09

Re: perl/cgi: populating a table in html, from a regex

Posted 24 November 2010 - 02:18 AM

For the "full name" on toor, note in the finger output I used as sample data that, if the tty id is preceded by a "*", it appears one column earlier than the "Tty" label in the header. Either make the "full name" field a column narrower and "tty" a column wider (so that the "*" falls within the "tty" field, where it belongs) or put in an extra A1 field for the "*" to appear in if it's present.

As for the weird values in the "Computer" field, can you post some sample finger output (in code tags, so spacing is preserved)? Identifying the correct column widths should be pretty quick and, once you've got the right field sizes, you can use an array slice in the map to discard any fields you're not interested in. (e.g.,
push @user_table_body, Tr(map { td($_) } @user[0..2, 4]);
if you only want the first three fields and the fifth.)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1