Today is Valentine’s day. Valentine’s day is all about love, and the internationally recognised symbol of love is the stylised heart. I love sed. This is probably why I spent this evening alone writing a filter to format text as ASCII hearts:

nick@pickle:~$ sed --posix -n -f hearts.sed < poem
     Shall        I comp
   are thee t   o a summer
 's day? Thou  art more love
ly and more temperate. Rough 
winds do shake the darling bu
ds of May, And summer's lease
  hath all too short a date.
    Sometime too hot the e
     ye of heaven shines
       , And often is 
         his gold co
           mplexio
             n d
              i
     mmed;        And ev
   ery fair f   rom fair s
 ometime decli nes, By chanc
e, or nature's changing cours
e untrimmed. But thy eternal 
summer shall not fade Nor los
 e possession of that fair t
   hou ow'st; Nor shall de
     ath brag thou wand'
       rest in his sha
         de, When in
            eterna
             l l
              i
     nes to        time 
   thou grow'   st, So lon
 g as men can  breathe or ey
es can see, So long lives thi
s, and this gives life to the
e............................
 ...........................
   .......................
     ...................
       ...............
         ...........
           .......
             ...
              .

You can download the script here: hearts.sed.

As far as I can tell, girls are mad keen on standards compliance. So I went out of my way to make this script POSIX compliant.

I’ve reproduced this labour of love below. As you can see, it demonstrates the elegance and practicality of sed as general purpose programming language:

: gather
/^[[:space:]]*$/d
s/[[:space:]]\{1,\}/ /g
/.\{251\}/{
  s/^\(.\{6\}\)\(.\{6\}\)/     \1       \2\n1/;P
  s/^.*\n1\(.\{10\}\)\(.\{10\}\)/   \1   \2\n2/;P
  s/^.*\n2\(.\{13\}\)\(.\{13\}\)/ \1 \2\n3/;P
  s/^.*\n3\(.\{29\}\)/\1\n4/;P
  s/^.*\n4\(.\{29\}\)/\1\n5/;P
  s/^.*\n5\(.\{29\}\)/\1\n6/;P
  s/^.*\n6\(.\{27\}\)/ \1\n7/;P
  s/^.*\n7\(.\{23\}\)/   \1\n8/;P
  s/^.*\n8\(.\{19\}\)/     \1\n9/;P
  s/^.*\n9\(.\{15\}\)/       \1\nA/;P
  s/^.*\nA\(.\{11\}\)/         \1\nB/;P
  s/^.*\nB\(.\{7\}\)/           \1\nC/;P
  s/^.*\nC\(.\{3\}\)/             \1\nD/;P
  s/^.*\nD\(.\)/              \1\n/;P
  $ { d; q }
  D
}
$ { s/$/\./; b gather }
N
s/\n\n*/ /g
b gather