I'm feelin’ upside down

You’ve probably run across upside-down words sıɥʇ ǝʞıl somewhere in your internet travels. There are several sites like this one that will take your text and flip it for you. I thought it would be fun to make a text flipper that I could use directly in any text editor or web input box. Here’s how it turned out.

First, you should know that flipped text isn’t really flipped; it’s just a character substitution that gives that appearance. For example, the letter p works as an upside-down d and vice-versa. Some letters are their own substitution: o is the obvious example, but s and z also work that way. The other letters use phonetic symbols, which are defined as Unicode characters, as substitutes. The most famous of these is the schwa (ə), which you may remember from school. On the Mac, you can see these characters by opening the Character Palette and navigating to the Phonetic Symbols set

The sites that offer text-flipping services use JavaScript to do the substitutions within your browser. Since I wanted a stand-alone text-flipper, I chose to write mine in Python. I call it flip and keep it in my ~/bin directory.

 1:  #!/usr/bin/python
 2:  # -*- coding: UTF-8 -*-
 3:  
 4:  from sys import stdin, stdout
 5:  
 6:  pchars = u"abcdefghijklmnopqrstuvwxyz,.?!'()[]{}"
 7:  fchars = u"ɐqɔpǝɟƃɥıɾʞlɯuodbɹsʇnʌʍxʎz'˙¿¡,)(][}{"
 8:  flipper = dict(zip(pchars, fchars))
 9:  
10:  def flip(s):
11:    charList = [ flipper.get(x, x) for x in s.lower() ]
12:    charList.reverse()
13:    return "".join(charList)
14:  
15:  stdout.write(flip(stdin.read()).encode('utf8'))

The weird comment in Line 2 tells Python to accept Unicode characters within the source code itself. Lines 6–8 define a dictionary called flipper that has the normal characters as the keys and the flipped characters as the values. There’s a cute Pythonic trick in these lines: after Lines 6 and 7 define strings of plain and flipped characters, Line 8 turns the two strings into a single dictionary by interleaving the characters with zip and then converting with dict.

Once the flipper dictionary is defined, the rest is easy. The list comprehension in Line 11 lower-cases the input string and then uses the get method to translate from plain to flipped characters. Characters that aren’t in the flipper dictionary--like the space character--are passed through unchanged. Line 12 reverses the list of flipped characters because we want plain to turn into uıɐld, not dlɐıu. Line 13 turns the list of characters into a string.

Line 15 puts everything together: it reads the input, flips the text, ensures that it has the proper encoding, and writes it out. Standard input and output are used, so flip will act as a normal Unix filter.

To use flip from within any text editing window or field, I’ve defined a TextExpander snippet with an abbreviation of ;fc and a shell script content of

#!/bin/bash
pbpaste | /Users/drang/bin/flip

When I type ;fc, TextExpander pipes whatever is on the clipboard to flip and replaces ;fc with the flipped version of the clipboard text. The normal way to use this snippet is to

  1. Type the text I want flipped
  2. Select it
  3. Cut it
  4. Type ;fc

If you don’t have TextExpander, you could invoke flip with an AppleScript,

set cmd to "pbpaste | /Users/drang/bin/flip"
do shell script cmd

or call it via FastScripts or some similar utility.

¡ʇxǝʇ ɹnoʎ ƃuıddılɟ unɟ ǝʌɐɥ

Update 7/17/09
Initially, I was converting the pchars and fchars strings to lists before applying zip to them, i.e.,

pchars = list(u"abcdefghijklmnopqrstuvwxyz,.?!'()[]{}")
fchars = list(u"ɐqɔpǝɟƃɥıɾʞlɯuodbɹsʇnʌʍxʎz'˙¿¡,)(][}{")

Reader John Lichtenstein pointed out that the conversion to lists was unnecessary; zip will work with any set of iterables, not just lists. That makes the code simpler.

¡uɥoɾ ‘sʞuɐɥʇ

Tags: