Contents: Chronological Listing Of Exercises
July 2, 2010
Although Scheme is a great language for the algorithmic exercises that we usually examine, I wrote this program in Awk, because of its good support for text munging:
export PRAXIS=/home/phil/praxis
awk ' # exercises in chronological order (page "chron")
BEGIN { itemsperpage = 30; FS = "\n"; RS = ""
split("Jan:Feb:Mar:Apr:May:Jun:Jul:Aug:Sep:Oct:Nov:Dec",
monthname, ":") }
$1 ~ /^number\t[1-9][0-9]*$/ {
for (i=1; i<=NF; i++)
if (split($i, f, /\t/) == 2)
val[f[1]] = f[2]
out[++nitems] = \
sprintf("<tr><td>%d</td><td>%02d %s %d</td>" \
"<td><a href=\"/%d/%02d/%02d/%s/\">%s</a>: %s</td>" \
"<td><a href=\"/%d/%02d/%02d/%s/\">exercise</a> " \
"<a href=\"/%d/%02d/%02d/%s/%d/\">solution</a> " \
"<a href=\"http://programmingpraxis.codepad.org/" \
"%s\">codepad</a></td></tr>",
val["number"], val["pubday"], monthname[val["pubmon"]],
val["pubyear"], val["pubyear"], val["pubmon"],
val["pubday"], val["file"], val["title"],
val["blurb"], val["pubyear"], val["pubmon"],
val["pubday"], val["file"], val["pubyear"],
val["pubmon"], val["pubday"], val["file"],
val["soln"], val["codepad"]) }
# END { for (i=1; i<=nitems; i++) {
# if (i % itemsperpage == 1)
# printheader(i, nitems)
# print ""; print out[i]
# if (i % itemsperpage == 0 || i == nitems)
# printfooter(i, nitems)
# if (i % itemsperpage == 0 && i != nitems)
# printseparator(i, nitems) } }
END { print "<table cellpadding=\"10\">"
for (i=1; i<=nitems; i++) {
print ""; print out[i] }
print "</table>" }
function ceiling(n) { if (int(n) == n) return n; else return int(n) + 1 }
function printheader(i, nitems) {
printf("%s", "<big><big>Page: ")
for (page=1; page<=ceiling(nitems/itemsperpage); page++) {
if (ceiling(i/itemsperpage) == page) printf(" %d", page)
else printf(" <a href=\"/chron/%d\">%d</a>", page, page) }
print "</big></big>"; print ""; print "<table>" }
function printfooter(i, nitems) { print ""; print "</table>" }
function printseparator(i, nitems) { print ""; print "<!--nextpage-->\n" }
' $PRAXIS/praxis.info > $PRAXIS/pages/chron
The BEGIN
action does some needed initialization. The main loop takes every record (maximal sequence of non-blank lines) beginning with the regular expression ^number\t[1-9][0-9]*$
, splits the lines into name/value pairs stored in the val
associative array, then builds an output line and stores it in the out
associative array, incrementing the nitems
variable as it does so. The END
action writes the table header, the output lines in order, and the table footer. The program that creates the list of exercises in reverse chronological order is the same, except that the END
action counts the i
variable down from nitems
to 1; it is not shown here.
Originally, I intended to put page breaks every thirty exercises, as in the original Contents page, but I decided instead to just put the entire listing on a single page, which is more convenient; after seeing the size of the permuted table of contents, it no longer seemed to matter that the chronological listing was too long. But I left the code to do that in the program source text, commented out, in case I change my mind some time in the future.
The code is available at http://programmingpraxis.codepad.org/KpvDEPnn.
[…] Praxis – Chronological Listing Of Exercises By Remco Niemeijer In today’s Programming Praxis exercise our goal is to replicate a script Phil wrote to generate chronological […]
My Haskell solution (see http://bonsaicode.wordpress.com/2010/07/02/programming-praxis-chronological-listing-of-exercises/ for a version with comments):