Prepending an Indefinite Article (a or an) in Front of a Word or Phrase

Today, I had to whip up a Django template tag to add “a” or “an” in front of a phrase.

It started off pretty easy — just use “an” when the first letter of the phrase is a vowel and otherwise use “a.” And then I remembered about abbreviations (“an HR department”), silent H words (“an honorable man”), and exceptions among a few O and U words (“a one-time offer” or “a union representative”), and suddenly it wasn’t so easy.

Fortunately I managed to find an excellent database of English words that includes pronunciations, and in no time at all I was able to generate a list of exceptions.

Here’s the final result, implemented as a custom django template tag (in my use case, I needed to able to wrap the original phrase in an HTML tag, so I couldn’t use a filter tag). This could also easily be a standalone Python function as well (literally by removing the @register.simple_tag decorator).

import re

@register.simple_tag
def with_indefinite_article(phrase, before_phrase="", after_phrase=""):
    silent_h_words = ["homage", "hour", "herb", "heir", "honest", "honor"]
    letters_with_initial_vowel_sound = ["a", "e", "f", "h", "i", "l", "m", "n", "o", "r", "s", "x"]
    vowels = ["a", "e", "i", "o", "u"]
    o_exceptions = ["once","one","oneness","ones","oneself","onetime"]
    u_exceptions = ["ubiquitous","uganda","ugandan","ukraine","ukrainian","ukulele","ukuleles","unanimous","unanimously","unicellular","unicorn","unicorns","unicycle","unicycles","unification","unified","uniform","uniformed","uniformly","uniforms","unify","unifying","unilateral","unilateralism","unilaterally","union","unionist","unionists","unionization","unionized","unionizing","unions","unique","uniquely","uniqueness","unisex","unison","unisons","unit","unitarian","unitary","unite","united","uniting","units","unity","universal","universally","universe","universes","universities","university","universitys","unix","uranium","urinalysis","urinary","urinate","urinating","urine","urologist","urologists","urology","uruguay","uruguayan","uruguays","usable","usage","usages","use","used","useful","usefully","usefulness","useless","usenet","user","users","uses","usual","usually","usurp","usurpation","usurped","usurper","usurping","usury","utah","utahn","utahns","utahs","utensil","utensils","uterine","utero","uterus","utilitarian","utilities","utility","utilitys","utilization","utilize","utilized","utilizes","utilizing","utopia","utopian","utopians","utopias"]

    # get rid of everything but letters and numbers and a few characters
    first_word = re.sub(r"[^A-Za-z0-9\-]", "", phrase.split()[0])
    first_letter = first_word[0].lower()

    # default to 'a'
    article = "a"

    if first_word.isupper() or (len(first_word) == 1):
        # if all caps or a single letter, we're going to assume it's an abbreviation
        if first_letter in letters_with_initial_vowel_sound:
            article = "an"
    elif first_letter == "h" and any( [re.match(r'(?i)%s' % w, first_word) for w in silent_h_words] ):
        article = "an"
    elif first_letter in vowels:
        if first_letter == 'e':
            article = "a" if first_word.lower().split('-')[0] == 'ewe' else "an"
        elif first_letter == 'o':
            article = "a" if first_word.lower().split('-')[0] in o_exceptions else "an"
        elif first_letter == 'u':
            article = "a" if first_word.lower().split('-')[0] in u_exceptions else "an"
        else:
            article = "an"

    return "%s %s%s%s" % (article, before_phrase, phrase, after_phrase)

Hopefully this will save someone who stumbles upon this some extra work down the road. If you find any bugs, please let me know in the comments.

1 comment

  1. atomless

    Saved me a lot of time. Very much appreciated. Thanks for sharing!

Post a comment

Contact Info
will not be published

include http://

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>