videogamer06 has asked for the wisdom of the Perl Monks concerning the following question:

ok, here's the deal. I need to know how to combine multiple fields of the same type. say i have this data in my text file.
csc, tech, base csc, comp, acm csc, mous, base the table should look something like below, but in an html table with +the appropriate rowspans. rs=rowspan, just usinf to fit on one line <r></r> means <tr></tr>, just using to fit on one line <r><td rs=3>csc</td><td rs=1>tech</td><td rs=2>base</td></r> <tr><td rs=1>comp</td></tr> <tr><td rs=1>mous</td><td rs=1>acm</td></tr> to get something like this in an html table |csc|tech|base| | |comp| | | |mous|acm |
any help would be appreciated!!!!!!!!!!!!!!!!

Replies are listed 'Best First'.
Re: printing a table in html using data read from a text file
by bjelli (Pilgrim) on Jun 08, 2001 at 14:04 UTC

    HTML::Table is a very handy module that gives you a table object which you can manipulate for a while before finally printing it out.

    The rows and columns in a HTML::Table are counted on a grid, starting at 1,1. Cells that span several columns and/or rows do not disturb the count:

    +---+---+---+---+---+
    |1/1|2/1|3/1|4/1|5/1|
    +---+---+---+---+---+
    |1/2|2/2|3/2|4/2|5/2|
    +   +---+---+---+---+
    |   |2/3|3/3    |5/3|
    +---+---+---+---+---+
    |1/4|2/4|3/4|4/4    |
    +---+---+---+       +
    |1/5|2/5|3/5|       |
    +---+---+---+---+---+

    Here's my test-data:

    csc,tech,base csc,comp,acm csc,mous,base new,this,that other,some,sing other,some,sels

    And the program:

    use SuperSplit; use HTML::Table; $data = supersplit_open( ',', 'table.txt');
    I first generate an array that holds the first column, in my example that's (csc,csc,csc,new,other,other). From that I compute a seconde array that hold the count of the words in the first column, here this is (3,0,0,1,2,0). (I bet someone here could turn this into a one-liner <kbd>;-)</kbd>
    @firstcol = map { $$_[0] } @$data; @numbers = (1) x scalar(@firstcol); # init to (1,1,1,...) for ($i = $#firstcol; $i > 0; $i--) { if ($firstcol[$i] eq $firstcol[$i-1]) { $numbers[$i-1] = $numbers[$i]+1; $numbers[$i] = 0; } }
    Then I generate the plain table (without spanning cells)
    $table = new HTML::Table; $table -> setBorder(2); foreach $row (@$data) { $table->addRow( @$row ); } # $table->print;
    And finally I walk down the first column and set the spanning:
    foreach $rowno (0..$#firstcol) { if ($numbers[$rowno]) { $table->setCellRowSpan($rowno+1, 1, $numbers[$rowno]); $table->setRowVAlign($rowno+1, "TOP") }; } $table->print;

    The output of the program:
    csctechbase
    compacm
    mousbase
    newthisthat
    othersomesing
    somesels

    Links and typos fixed june 11, thanks to jeffa

    --
    Brigitte    'I never met a chocolate I didnt like'    Jellinek
    http://www.horus.com/~bjelli/         http://perlwelt.horus.at
      Thanks! I took your code as an inspiration, and coded it for my next Web Techniques column, and will credit you in the column. Thanks for the idea!

      To play with the program, click on the column headers once for ascending sort, twice for descending. It autodetects whether there should be an alpha sort or a numeric sort. Yeah, it's not the best, but the program's only 70 lines of code or so.

      -- Randal L. Schwartz, Perl hacker

Re: printing a table in html using data read from a text file
by jeroenes (Priest) on Jun 08, 2001 at 12:10 UTC
    There are tools available for the data retrieval and HTML-table print:
    use SuperSplit; use CGI qw/:html/; $data = supersplit_open( ', ', $data_file ); print table Tr [map td( $_ ), @$data] ;
    Hope this helps,

    Jeroen
    "We are not alone"(FZ)
    Update: After reading crazyinsomniac's updates, I really need to give credits to merlyn, who showed me the distributive properties of CGI functions.
    Update 2: Forgot to paste the $_. bjelli++ for noting...

      jeroenes second updated fixed the problem I pointed out here.

(crazyinsomniac) Re: printing a table in html using data read from a text file
by crazyinsomniac (Prior) on Jun 08, 2001 at 11:11 UTC
    Take a look at nested data structures, perlref, perlreftut, and of course perldata.

    What you wanna do(IMHO) is create a hash of arrays(a plain hash will do).

    functions of interest perlfunc:scalar, perlfunc:keys, perlfunc:shift, perlfunc:push, perlfunc:join, and perlfunc:split.

    This is more than enough information to get you started (and more).

    #!/usr/bin/perl -w #file://videogamer06.pl #html table, appropriate rowspans. use strict; my %crap = (); my @all3; while(<DATA>) { @all3 = split(',',$_); push @{$crap{shift @all3}}, @all3; } foreach my $key (keys %crap) { print '$key-', @{$crap{$key}}, "\n"; } print "\n", '-' x 60, "\n"; foreach my $key (keys %crap) { print $key,"\t|"; my @twod = @{$crap{$key}}; print join("\t|", @twod); } print "\n", '-' x 60, "\n"; foreach my $key (keys %crap) { print $key; my @twod = @{$crap{$key}}; for my $ix (0..$#twod) { print "\t|", $twod[$ix]; } } #|csc|tech|base| #| |comp| | #| |mous|acm | __DATA__ csc, tech, base csc, comp, acm csc, mous, base
    UPDATE:
    I reviewed my post, and I found a serious mistake. push @{$crap{shift @all3}}, @all3; should have been push @{$crap{shift @all3}}, \@all3;
    Since I made this mistake early on, all my subsequent 'examples' are incorrect. I apologize for this hastiness. I will leave the incorrect code there, but here is hybrid correction:
    #!/usr/bin/perl -w #file://www.kibo.com.pl use strict; my @all3=(); my %crap=(); while(<DATA>) { @all3 = split(',',$_); push @{$crap{shift @all3}}, \@all3; } foreach my $key (keys %crap) { print $key,"\t|\n"; my @twod = @{$crap{$key}}; foreach my $reference (@twod) { my @twod2 = @{$reference}; print "\t|", join("\t|", @twod2), "\n"; } print "\n",'-' x 79,"\n"; } __DATA__ a,3,4 a,30,04 a,300,004 a,3000,400 b,3,4 b,30,04 b,300,004 c,3000,400

    Anyway, here is a working piece of code (for the actual table). It is a little off spec, but it keeps the 'look' and the logic is easier.
    Results wil look like:

    foo|       |
       |abc|def|
       |fed|era|
    #!/usr/bin/perl -w #file://working.snippet.pl use strict; my %crap = (); my @all3; while(<DATA>) { chomp; @all3 = split(',', $_ ); push @{$crap{shift @all3}}, \@all3; } print "\n", '-' x 60, "\n"; print "<TABLE BORDER=66>\n"; foreach my $key (keys %crap) { my @twod = @{$crap{$key}}; my $rowspan = 2+$#twod; my $colspan = 1+$#{$twod[0]}; print "<TR><TD ROWSPAN=", $rowspan, ">\n", $key, "</TD>\n"; print "<TD COLSPAN=", $colspan, ">&nbsp;</TD></TR>\n"; for my $ref (@twod) { my @hef = @{$ref}; print "<TR>\n"; for my $hef (@hef) { print "<TD>\n $hef \n</TD>\n"; } print "</TR>\n"; } } print "</TABLE>\n"; __DATA__ csc, tech, base csc, comp, acm csc, mous, base dcsc, mo0us, bas0e ecsc, mous, base csc, mou0s, baase bcsc, mo500us, 0bas0e bcsc, m4o0us, b0as0e bcsc, mo1us, ba0se bcsc, m2o0us, b0as0e
    UPDATE:
    You know, sometimes, late at night, I go beyond idiot.
    Please use jeroenes suggestion, as it is brilliant!

     
    ___crazyinsomniac_______________________________________
    Disclaimer: Don't blame. It came from inside the void

    perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

Re: printing a table in html using data read from a text file
by tachyon (Chancellor) on Jun 08, 2001 at 11:24 UTC

    What you seem to be asking for is "how do I avoid printing duplicate fields". The answer to this is by using a hash. A hash can not have identical keys so as we iterate over the fields we check for its prior existence via a hash key. If the key already exists the field is a duplicate, if not it is unique. If unique we add it to our hash keys so next time it will be recognised as a duplicate.

    This will dump a table like you want....

    tachyon

    my %dup; # duplicate charachters hash print "<TABLE BORDER='1'>\n"; for (<DATA>) { chomp; next if /^\s*$/; my @elements = split", ",$_; map{exists $dup{$_} ? $_= "&nbsp;" : $dup{$_}++ }@elements; print_row(@elements); } print "</TABLE>\n"; sub print_row { print"<TR>"; print"<TD>$_</TD>" for @_; print"</TR>\n"; } __DATA__ csc, tech, base csc, comp, acm csc, mous, base

    Update

    Here is the code in plain perl form. I have added this because it was privately suggested that my initial post was totally lacking in explanation and too complicated. Too much perl lately I guess...

    # start by printing the opening table token print "<TABLE BORDER='1'>\n"; # now lets iterate over the lines of data foreach my $line(<DATA>) { # chomp of the \n from each line chomp($line); # ignore blank lines in the data next if $line =~ m/^\s*$/; # split the line into an array of elements my @elements = split", ",$line; # now iterate over the elements, if the element has # already been seen then set it to &nbsp; # which is the HTML token for a space, otherwise # add the element to our duplicates hash # I did this using map as shown: # map{exists $dup{$_} ? $_= "&nbsp;" : $dup{$_}++ }@elements; # in this context map is just a fancy way of # writing a loop structure. foreach (@elements) { # the magical $_ is assigned to each element # of our array @elements # the (condition) ? do this : (else) do that # construct is a one line version of the # if (cond) {do this} else {do that} below # so the map has the effect of seven lines... if (exists $dup{$_}) { # $_ is magical -> by changing $_ # we change this element of @elements $_ = "&nbsp;"; } else { # define a new key of our %dup hash # you can just do $dup{$_}++ to assign # a value of one to $dup{$_} but this # is more obvious $dup{$_} = "seen, so define $_ key"; } } # print out the line via our sub, formating # each element for a HTML table print_row(@elements); } print "</TABLE>\n"; sub print_row { print"<TR>"; # @elements is passed to sub via @_ array, this # print"<TD>$_</TD>" for @_; # is just short form for: foreach my $element(@_) { print"<TD>$element</TD>" } print"</TR>\n"; } __DATA__ csc, tech, base csc, comp, acm csc, mous, base
      sub print_row { print"<TR>"; print"<TD>$_</TD>" for @_; print"</TR>\n"; }
      For stuff like this, I so love using the stuff in CGI.pm. It's so slick to be able to say
      print TR( td( \@_ ) );
      Or, if I want to build a table at once, do:
      my @rows; for ( blah blah ) { ... push( @rows, TR( td( \@_ ) ); } print table( @rows );

      xoxo,
      Andy

      %_=split/;/,".;;n;u;e;ot;t;her;c; ".   #   Andy Lester
      'Perl ;@; a;a;j;m;er;y;t;p;n;d;s;o;'.  #   http://petdance.com
      "hack";print map delete$_{$_},split//,q<   andy@petdance.com   >