[comp.lang.perl] Challenge: Generalized automatic numbering

al@ee.pitt.edu (A. Martello) (02/06/91)

I wrote the man page, who's going write the perl "one-liner"?  (just
kidding) Anyway, I am looking for some perl code to perform the
following.  Anyone have anything lying around that comes close (or
feel like hacking it together)?

It is likely that there are ambiguities and errors in the description
below.

*******************************************************************
       Alan R. Martello        Electrical Engineering Dept.
        al@ee.pitt.edu           University of Pittsburgh
*******************************************************************

How about a perl script to scan an input file and replace occurrences
of a 'special char' with a number.  Simple enough?  How about being
able to have "nested" numbers (like you'd use in an outline).

There are (so far) 6 forms which must be understood 
(where 'x' is the level number [1-9] and $SPECIAL_CHAR = '\\').

   \x       print the index at level x
   \x+      print the index at level x then increment it
   \x-      print the index at level x then decrement it
   \x=val   set x equal to val and print it (where val is a 
            decimal number which matches /[0-9]+/
   \\       insert SPECIAL_CHAR (only useful if SPECIAL_CHAR 
            appears directly before a number in the input stream)
   \xF="string"  set the format string for level x to string

The special char may be set in the file itself to character x
ONLY if the first 3 characters in the file are \=x 

All 4 printing forms can also have a 'non-printing' version where the
$SPECIAL_CHAR has a '!' after it but before the 'x'.

If an 'index' has not been initialized, its value is one.

To be more general purpose than just outputting numbers, each level
can have its own format indicated by setting \F="format_string" where
then format_string is a normal string with the addition that the first
character in format string defines how to output the index value
within the string and ALL occurrences of $SPECIAL_CHAR in the string
are replaced with the indicated index.  Everything else in the format
string is copied verbatim in the replacement process.

Valid first characters which describe how to output the index are:
  'R'  uppercase roman
  'r'  lowercase roman
  'N'  integers
  'A'  uppercase alphabetic (1 == 'A', 2 == 'B', etc.)
  'a'  lowercase alphabetic (1 == 'a', 2 == 'b', etc.)

Program Usage
-------------
Replaces occurrences of special format strings in stdin
with numbers and writes its result to stdout.

numstream [SPECIAL_CHAR [FormatLevel_1 FormatLevel_2 .... ]]

The default SPECIAL_CHAR is '\\' and the default FormatLevel[1..9]
are "N\"

EXAMPLES
--------

Input:  Exam questions                      
----------------------
\1History

\2+Who is the first president?
\2+Who is buried in Grant's tomb?

\2=1\1Philosophy

\2+Who was Nietzsche?
\2-Why am I here? (see question \2+)
\2+Is there a god?

Command (with shell quoting): 
-----------------------------
numstream \\ "NSection \\: " "NQuestion \\: "
This would be the same as adding the following to the top of the input:
\1F="NSection \: "\2F="NQuestion \: "

Output:
-------
Section 1: History

Question 1: Who is the first president?
Question 2: Who is buried in Grant's tomb?

Section 2: Philosophy

Question 1: Who was Nietzsche?
Question 2: Why am I here? (see question 1)
Question 3: Is there a god?

Input: Outline
--------------

@1+ Making Widgets
@2+ Specifying Widgets
@2+ Designing Widgets
@2+ Manufacturing Widgets
@3+ How widgets differ from ping-pong balls
@2+ Long Term Viability of Widgets

@1+ Making Computers
@2+ Why Computers Have No Future

Command (with shell quoting): 
-----------------------------
numstream \@ "R@." "    A@." "        N@."
This would be the same as adding the following to the top of the input:
\=@\1F="R@."
\2F="    A@."
\3F="        N@."

Output:
-------
I. Making Widgets
    A. Specifying Widgets
    B. Designing Widgets
    C. Manufacturing Widgets
        1. How widgets differ from ping-pong balls
    D. Long Term Viability of Widgets

II. Making Computers
    A. Why Computers Have No Future
---------------------------end of message------------------------------------

mooring@grimoire.uucp (Ed Mooring) (02/08/91)

In article <9917@pitt.UUCP> al@ee.pitt.edu (A. Martello) writes:
>I wrote the man page, who's going write the perl "one-liner"?  (just
>kidding) Anyway, I am looking for some perl code to perform the
>following.  Anyone have anything lying around that comes close (or
>feel like hacking it together)?
>
>It is likely that there are ambiguities and errors in the description
>below.
	[self-characterization deleted]
>How about a perl script to scan an input file and replace occurrences
>of a 'special char' with a number.  Simple enough?  How about being
>able to have "nested" numbers (like you'd use in an outline).
>
	[specification removed for brevity's sake]

This isn't quite what you asked for, but close.  I needed a crude text
formatter for a bunch of people using different machines, with no time 
to train them to use a real formatter, so I put this together.

The style and technique are amateurish because it's the very first perl
program I ever wrote, two days after I brought up version 2.0, I 
promise I'd do better now :-)

#!/usr/local/bin/perl
#
#  Quick perl script to replace commands of the form
#  @L# with the pseudo mil-spec section numbering form.
#
#  Added @LB	to begin a list
#	 @LI	to insert a list item (#.)
#        @LE    to end a list
$ListLevel = -1;
while (<>) {
	if (($Spaces, $Level, $Etc) = /^(\s*)@L(\d+)(.*)/) {
		die "That's not a level!" unless (length($Level));
		$Level -= 1;			# make up for 0 starting arrays
		for ($i = $Level+1; $i <= $#depth; $i++) {
			@depth[$i]=0;
		}
		@depth[$Level] += 1;
		$#depth = $Level;
		print $Spaces, join ('.',@depth),$Etc, "\n";
		die "Unterminated list" unless ($ListLevel == -1);
	}
	elsif (/@LB/) { # start a list
		die "Nested lists are not allowed" unless ($ListLevel == -1);
		$ListLevel = 0;
	}
	elsif (($spaces, $rest) = /^(\s*)@LI(.*)/) { # list item
		$ListLevel += 1;
		die "List item not between @LB and @LE " unless ($ListLevel > 0);
		print $spaces,$ListLevel,".",$rest,"\n";
	}
	elsif (/@LE/) { #end a list
		die "List ended without having begun" unless ($ListLevel >= 0);
		$ListLevel = -1;
	}
	else {
		print;
	}
}
exit 0;
----------
Ed Mooring (mooring@grimoire.tymnet.com 408-999-7504)

al@jupiter.ee.pitt.edu (A. Martello) (02/19/91)

Felix Lee (flee@guardian.cs.psu.edu) has taken my challenge on
and generated something which has surpassed even my expectations....

Stay tuned (Felix should be releasing things shortly)...

*******************************************************************
       Alan R. Martello        Electrical Engineering Dept.
        al@ee.pitt.edu           University of Pittsburgh
*******************************************************************