Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re: Need help with filling a complicated data structure: Epilog

by Lady_Aleena (Priest)
on Jan 19, 2015 at 07:02 UTC ( [id://1113707]=note: print w/replies, xml ) Need Help??


in reply to Need help with filling a complicated data structure

Dear hdb and ig, I know it is over a year since you did so much work to help me get my data to look the way I wanted it to look. About a month ago, I finally sat down with your work, and forced myself to get it incorporated come hell or high water. Below is the result of your hard work with very little done by me except to do some minor modifications in expanding the scope.

hdb, I used your work in Re: Need help with filling a complicated data structure to make my lists.

ig, I used your work in Re^3: Need help with filling a complicated data structure to group the lines together for my lists and tables. I also used it when it came time to parse the tables. Don't worry, I didn't include tables in my original post. I had not used for like you did before now. I had never taken it apart to understand it until your work made me look into it. So thank you for the push I needed to learn something new.

So, at long last, here is the code which effectively solved my problem with your help. I am so very thankful for your work, sorry it comes so late.

# Begin subroutines used in 'story' below. # 'convert_string' finds ^words between carrots^ and matches them to k +eys in $line_magic # and does replacements. sub convert_string { my ($string, $line_magic) = @_; $string =~ s/\^([\w\s\.\#]+)\^/exists $line_magic->{$1} ? $line_magi +c->{$1} : $1/ge; return $string; } # 'row_line' returns the array ref of a row of cells which I use in 't +able_opts'. sub row_line { my ($line, $opt) = @_; my @row = split(/\|/, $line); my $row_data; for my $cell (@row) { push @{$row_data}, $cell =~ /^r(\d)\s(.+)$/ ? [inline(convert_stri +ng($2, $opt->{'line magic'})), { 'rowspan' => $1 }] : $cell =~ /^c(\d)\s(.+)$/ ? [inline(convert_stri +ng($2, $opt->{'line magic'})), { 'colspan' => $1 }] : inline(convert_string($cell, $opt->{'line magic +'})); } return $row_data; } # 'table_opts' returns all of the options for my separate 'table' func +tion (not included here). # In 'story' below, I group all lines beginning with a | and them pars +e them here. # [ig] showed me how to group lines together in a loop which I used he +re and in 'story'. # || the_tables_class # |! The table's caption # |* The|table's|headings # |+ A|row|which|starts|with|a|heading # |- A|now|which|doesn't start|with|a|heading sub table_opts { my ($lines, $opt) = @_; my $table_opts; my $match = '|!*+-'; for (my $lineno = 0; $lineno < @$lines; $lineno++) { my $line = $lines->[$lineno]; $match = substr($line, 0, 1); if ($match eq '|') { $line =~ s/^\| (.+)$/$1/; $table_opts->{'class'} = $line; } elsif ($match eq '!') { $line =~ s/^\! (.+)$/$1/; $table_opts->{'caption'} = inline(convert_string($line), $opt->{ +'line magic'}); } elsif ($match eq '*') { $line =~ s/^\* (.+)$/$1/; push @{$table_opts->{'rows'}}, ['header', row_line($line, $opt)] +; } elsif ($match =~ /[\+-]/) { my $start = $lineno; my $end = $lineno; $end++ while ($end < $#$lines and $lines->[$end + 1] =~ /^[$matc +h]/); my @table_rows = map { $_ =~ s/^[\+-] (.+)/$1/; row_line($_, $opt); } @{$lines}[$start..$end]; my $type = $match =~ /\+/ ? 'whead' : 'data'; push @{$table_opts->{'rows'}}, [$type, \@table_rows]; $lineno = $end; } $match = '*+-'; } return $table_opts; } # 'type' and 'get_list' are written by [hdb]. [ig] wrote a version too +. # 'get_list' parses the groups of lines which begin with a * or a # in + my data. # The returned list is plugged into my 'list' function which is not in +cluded here. sub type { my %type = ( '*' => 'u', '#' => 'o' ); $type{ substr shift, -1 } } sub get_list { my ($list, $opt) = @_; $list = [ map (inline(convert_string($_, $opt->{'line magic'})), + @$list) ]; my @lines = map { /([*#]*)(\d*)\s+(.*)/; $2 ? [$1, [$3, {value => $2}]] : [$1, $3] } @$list; my $maxlevel = max map { length $_->[0] } @lines; while( $maxlevel ) { my @indices = grep { $maxlevel == length $lines[$_]->[0] } 0..@lin +es - 1; while( @indices ) { my $end = pop @indices; my $start = $end; $start = pop @indices while @indices and $indices[-1] == $start- +1; my $sublist = [ type($lines[$start]->[0]), [ map { $_->[1] } splice @lines, $start, $end-$start + 1 ] ]; $lines[$start-1]->[1] = [ $lines[$start-1]->[1], { 'inlist' => $ +sublist} ] if $maxlevel > 1; splice @lines, $start, 0, $sublist if $maxlevel == 1; } $maxlevel--; } @lines = grep { $_->[0] } @lines; } # 'heading_w_links' is something I wrote earlier. # It adds links to wikipedia and google under the heading of a section +. sub heading_w_links { my ($tab, $level, $text) = @_; my ($heading, $wikipedia) = split(/\|/,$text); my $article = $wikipedia ? $wikipedia : $heading; heading($tab, $level, textify($heading), { id => idify($heading) }); paragraph($tab + 1, external_links([['Wikipedia',filify($article)],[ +'Google',searchify($heading)]]), { 'style' => 'float: right' } ); } # End subroutines used in 'story' below. sub story { my ($source, $opt) = @_; # Start table of contents and sections. my $inc = 0; my $cols = 0; my @sections; my @toc; while (my $line = <$source>) { chomp($line); next if !$line; if ($line =~ /^2 /) { my ($number,$text) = split(/ /,$line,2); $text =~ s/ \+$//; push @toc, [anchor(textify($text), { href => '#'.idify($text) }) +]; } if ($line =~ /^3 /) { my ($number,$text) = split(/ /,$line,2); $text =~ s/ \+$//; $toc[$inc-1][1]->{inlist}[0] = 'u'; push @{$toc[$inc-1][1]->{inlist}[1]}, anchor(textify($text), { h +ref => '#'.idify($text) }); #$toc[$inc-1][1]->{inlist}[2]{'style'} = 'font-size: smaller;'; } $inc++ if $line =~ /^2 /; $cols++ if $line =~ /^(?:2|3) /; push @{$sections[$inc]}, $line; } # End table of contents and sections. # Start parsing the sections. my $tab = 2; my $match = '\*#|'; # These characters denote lists or tables. $inc = 0; for my $section (@sections) { if ($section) { section($tab, sub { $tab++; # I'd never used for like the following before now. for (my $lineno = 0; $lineno < @$section; $lineno++) { my $line = $section->[$lineno]; if ($line =~ /^[$match]/) { # $match is shortened to one character for future lines +to match. # It also tells the parser where to send the grouped lin +es, # table (|) or list (* or #). $match = substr($line, 0, 1); my $start = $lineno; my $end = $lineno; $end++ while ($end < $#$section and $section->[$end+1] = +~ /^[$match]/); my @list_lines = @{$section}[$start..$end]; # lines beginning with | all belong to a table and are s +ent to 'table_opt'. if ($match eq '|') { my @list = map { $_ =~ s/^\|(.+)/$1/; $_; } @list_line +s; my $opts = table_opts(\@list, $opt); table($tab + 1, $opts); } # lines beginning with a * or # belong to a list and are + sent to 'get_list'. else { my $class = $list_lines[0] =~ s/^[\*#]\| (.+)$/$1/ ? s +hift @list_lines : undef; my @list = get_list(\@list_lines, $opt); $list[0][2]->{'class'} = $class ? $class : undef; list($tab + 1, @{$list[0]}); } $lineno = $end; # Reset $match after a set of lines is grouped, ready fo +r next grouping. $match = '\*#|'; } else { heading_w_links($tab, $1, $2), next if $line =~ /^([1-6] +)\s+(.+) \+$/; heading($tab, $1, textify($2), { id => idify($2) }), nex +t if $line =~ /^([1-6])\s+(.+)/; div($tab, $2, { 'class' => "h$1" }), next if $line =~ /^ +([7-8])\s+(.+)/; $opt->{'doc magic'}->{$1}->(), next if $line =~ /^&\s+(. ++)/; line($tab + 1, $line), next if $line =~ /^<.+>/; line($tab + 1, "<$line>"), next if $line =~ /^[bh]r$/; blockquote($tab + 1, inline(convert_string($1, $opt->{'l +ine magic'}))), next if $line =~ /^bq\s(.+)/; # paragraphs paragraph($tab + 1, inline(convert_string($1, $opt->{'li +ne magic'})), { class => 'stanza', break => '\|' }), next if $line =~ + /^stanza (.+)$/; paragraph($tab + 1, inline(convert_string($2, $opt->{'li +ne magic'})), { class => "indent$1"}), next if $line =~ /^\>(\d+) ( +.+)$/; paragraph($tab + 1, inline(convert_string($line, $opt->{ +'line magic'})), { class => 'author' }), next if $line =~ /^(?:by|wit +h|from|as) /; paragraph($tab + 1, inline(convert_string($line, $opt->{ +'line magic'}))); } } $tab--; }); } my $toc_start = $opt->{'toc at'} ? $opt->{'toc at'} : 3; if ($inc == 0 && $cols >= $toc_start) { nav($tab, sub { my $class = get_columns(4, $cols); list($tab + 2, 'u', \@toc, { class => $class }); }, { heading => [2, 'Table of contents'], class => 'contents'} ) +; } $inc++; } # End parsing sections. }

hdb and ig, you helped me a lot! Thank you again! (I just hope my comments are clear enough, and my code makes sense.)

No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
Lady Aleena

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1113707]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-25 07:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found