SPUG: Better way to sort POD list-items?

Tim Maher tim at consultix-inc.com
Thu Mar 11 23:33:44 CST 2004


SPUGaholics,

I just found a need to dash off the following script, in order to
sort the glossary entries of the book I'm working on into
alphabetical order.

Seems like there should be an easier way!

Anybody got a cleaner technique for associating the item labels
with their associated data? I think I used to know a trick with
split() to do that, but if so I sure can't remember it now ...

For those who don't know POD, the list format is:

=item 1.

This is item 1

=item 2.

This is item 2

and so forth.

The script below assumes its input starts with the first "=item label" and
ends with the data for the last item.  That's easily arranged in vim with a
line like:

        :33,47!  sort_pod_items

*--------------------------------------------------------------------------*
| Tim Maher, CEO     (206) 781-UNIX      (866) DOC-PERL     (866) DOC-UNIX |
| tim(AT)Consultix-Inc.Com  http://TeachMePerl.Com  http://TeachMeUnix.Com |
*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-*
|  Classes: Perl Prog. plus Perl Modules, 4/5-4/8 ;  Template Toolkit: TBA |
|  Watch for my Manning book: "Minimal Perl for Shell Users & Programmers" |
*--------------------------------------------------------------------------*

#! /usr/bin/perl -wl
# sort_pod_items
# Tim Maher, tim at teachmeperl.com
# Thu Mar 11 21:13:40 PST 2004

# Quick and dirty program to sort POD list items into ASCIIbetical order
# Doesn't handle nested lists yet, and is in dire need of a more elegant way
# to get item-labels hooked together with their contents

$/=undef;

# Runs in file-slurping mode, so all data presented at once to implicit loop
$_=<DATA>;

# First, split lines into '=item' labels for POD-list items,
# followed by associated contents

@fields= split /(^=item[^\n]*?\n)/m, $_;

# Now join labels with following contents, so each such pair is in one chunk
# Input array of 10 items reduced to output array of 5, etc.

for ( $i=0; $i < @fields; $i++ ) {
        ( $fields[$i] =~ /^=item\b/ )  and 
                push @fields2, "$fields[$i]$fields[$i++ + 1]";
}

# Now use Schwartzian Transform to sort by labels of list items and print

print map { $_->[1] }
  sort { $a->[0] cmp $b->[0] }
  map {
     if ( $_ =~ /^=item\s+([^\n]+)\n/ ) {   # $1 is label for list item
            [ $1 , $_ ]
     } else {
            die "Bad data: records must start with =item\n";
     }
 } @fields2 ;

 __DATA__
=item This

and stuff was written

=item What

more drivel here

=item Other

getting the idea?

=item That's all

the end




More information about the spug-list mailing list