download notebook

Valentine's Day bonus notebook!

Edgar Allan Poe wrote A Valentine in 1846. The poem is below. Notice the first clause: "For her this rhyme is pennned..."

Who is the subject of Poe's poem?

The poem is an acrostic, which is a kind of simple code. The nth letter of the nth line of the poem spells out the answer. That is, take the first letter from the first line, the second letter from the second line, ...

Can you write a python program to decode the poem? In your final code block, spell out the name of the subject of the poem. You will not know where to capitalize or insert spaces, so just print out the string of letters. Then see if you can figure out the name by staring at it. (Or trying Google.)

There are lots of ways you could do this. Give it a try! (My solution is below.)

A few notes:

  1. The 'nth' element of a line does not include spaces or punctuation. One approach is to strip out the spaces and punctuation, then count.
  2. The string function splitlines() may be helpful. Look it up in the documentation if you are curious.
  3. The string function isalpha() is True if all the characters in a string are alphabetic.
poe_poem = """For her this rhyme is penned, whose luminous eyes,
Brightly expressive as the twins of Loeda.
Shall find her own sweet name, that, nestling lies
Upon, the page, enwrapped from every reader.
Search narrowly the lines! — they hold a treasure
Divine—a talisman—an amulet
That must be worn at heart. Search well the measure
The words—the syllables! Do not forget
The trivialest point, or you may lose your labor!
And yet there is in this no Gordian knot
Which one might not undo without a saber,
If one could merely comprehend the plot.
Enwritten upon the leaf where now are peering
Eyes scintillating soul, there lies perdus
Three eloquent words oft uttered in the hearing
Of poets, by poets as the name is a poet's, too.
Its letters, although naturally lying
Like the knight Pinto—Mendez Ferdinando
Still form a synonym for Truth. Cease trying!
You will not read the riddle, though you do the best you can do."""













Break the poem into lines

The splitlines() function will break the string at the line break character \n. We could also use split('\n').

# pp = poe_poe.split('\n')

pp = poe_poem.splitlines()
pp
['For her this rhyme is penned, whose luminous eyes,',
 'Brightly expressive as the twins of Loeda.',
 'Shall find her own sweet name, that, nestling lies',
 'Upon, the page, enwrapped from every reader.',
 'Search narrowly the lines! — they hold a treasure',
 'Divine—a talisman—an amulet',
 'That must be worn at heart. Search well the measure',
 'The words—the syllables! Do not forget',
 'The trivialest point, or you may lose your labor!',
 'And yet there is in this no Gordian knot',
 'Which one might not undo without a saber,',
 'If one could merely comprehend the plot.',
 'Enwritten upon the leaf where now are peering',
 'Eyes scintillating soul, there lies perdus',
 'Three eloquent words oft uttered in the hearing',
 "Of poets, by poets as the name is a poet's, too.",
 'Its letters, although naturally lying',
 'Like the knight Pinto—Mendez Ferdinando',
 'Still form a synonym for Truth. Cease trying!',
 'You will not read the riddle, though you do the best you can do.']
type(pp)
list

Now we have a list, where each element is one line of the poem.

A first try

Let's use enumerate to cycle through the list and see what we have. Notice that I am using the end option of print() to put all the letters on the same line.

for i,l in enumerate(pp):
    print(l[i], end=' ')
F r a n c e u d i h m d o a   e h i y h

Hmmm, I see France. That looks promising. The rest looks pretty bad. What's wrong?

I'm counting spaces and punctuation!

A second try: no spaces

I'll use the replace() method of string to strip out the spaces.

for i,l in enumerate(pp):
    print(l.replace(" ", "")[i], end=' ')
F r a n c e s s a r g e n t o a u o o d

Aha! I see Frances Sargent...but then some more junk. I still need to get rid of punctuation.

A third try: no spaces, no punctuation

I couldn't figure out a clean one-liner here. A little Googling shows a few tricks, but I figured I would take some time to practice writing functions.

I am using the .join() string function to take the list and return is as a string. I could have just returned the list — I would have gotten the same answer, because the [] access operator works the same for lists and strings.

def clean_line(l):
    """
    Take a string and return a string without punctuation or spaces.
    """
    temp = [c for c in l if c.isalpha()==1]
    return ''.join(temp)
for i,l in enumerate(pp):
    print(clean_line(l)[i], end=' ')
F r a n c e s s a r g e n t o s g o o d

Success! Poe is writing about Frances Sargent Osgood.

I really like the tidbit that Poe misspelled her name in the first first edition.