2
\$\begingroup\$

This is only my second Python script, so let me have it! If anything seems off in style or implementation, please nit pick away. I want to learn. I know it could've been done in less lines of code without making separate functions and whatnot, but I wanted to approach it like I would an actual project.

#!/bin/usr/python
from sys import exit

def print_help():
    print("")
    print("--------------------------------")
    print(" Command   |  Description")
    print("--------------------------------")
    print(" -h        |  Print help list")
    print(" -x        |  Exit program")
    print("--------------------------------")
    print("")

def is_valid_word(word):
    return word and word.isalpha()

def is_valid_string(string):
    for word in string.split(" "):
        if not is_valid_word(word):
            return False
    return True

def get_pig_latin(string):
    vowels = "aeiou"
    built = ""
    for word in string.split(" "):
        if len(word) < 2 or word[0] in vowels:
            built += word + "tay"
        else:
            temp = word
            while temp[0] not in (vowels + "y"):
                temp = temp[1:] + temp[0]
            built += temp + "ay"
        built += " "
    built = built[0].upper() + built[1:]
    return built

def print_title():
    print("")
    print("--------------------------------")
    print("----- PIG LATIN TRANSLATOR -----")
    print("--------------------------------")
    print("Type -h for help")
    print("")

def run():
    commands = { "-h" : print_help, 
                 "-x" : exit }
    print_title()
    while True:
        input = raw_input(":: ").strip().lower()
        if input in commands:
            commands[input]()
        elif is_valid_string(input):
            print("-> " + get_pig_latin(input) + "\n")
        else:
            print("   Unrecognized word or command.\n")

if __name__ == "__main__":
    run()
\$\endgroup\$
  • 2
    \$\begingroup\$ @tintinmj This is Python2 not Python3. raw_input is in Python2 not Python3 \$\endgroup\$ – Aseem Bansal Aug 26 '13 at 6:27
  • 1
    \$\begingroup\$ Simplify is_valid_string() with the all() function. \$\endgroup\$ – 200_success Aug 26 '13 at 7:11
  • \$\begingroup\$ word and word.isalpha() can be replaced with word.isalpha() \$\endgroup\$ – flornquake Aug 26 '13 at 8:16
  • \$\begingroup\$ @AseemBansal yes I realize that later, but then I can't roll back my edit. \$\endgroup\$ – Anirban Nag 'tintinmj' Aug 26 '13 at 12:55
  • \$\begingroup\$ @AseemBansal Is there a more "Python 3" way of doing raw_input()? \$\endgroup\$ – asteri Aug 26 '13 at 13:16
3
\$\begingroup\$

Not essential but I would find it neater to make a function that translates a single word, then join those together. You should also deal with the case of a word containing no vowels or 'y', which currently gets your programme stuck in an infinite loop.

def get_pig_latin(string):
    return ' '.join(map(translate_word, string.split(' '))).upper()

def translate_word(word):
    vowels = "aeiou"
    if len(word) < 2 or word[0] in vowels:
        return word + 'tay'
    elif contains_any(word, vowels + 'y'):
        while word[0] not in (vowels + 'y'):
            word = word[1:] + word[0]
        return word + 'ay'
    else:
        return '???'

Then add docstrings to your functions.

EDIT: It might be better to use a for loop instead...

def translate_word(word):
    if len(word) < 2 or word[0] in 'aeiou':
        return word + 'tay'
    for i, ch in enumerate(word):
        if ch in 'aeiouy':
            return word[i:] + word[:i] + 'ay'
    return '???'

You could also consider building the string validation into your translation function with a user-defined exception:

class TranslationError(Exception):
    def __init__(self, value):
        self.value = value

def translate(word):
    if word.isalpha():
        if len(word) < 2 or word[0] in 'aeiou':
            return word + 'tay'
        for i, ch in enumerate(word):
            if ch in 'aeiouy':
                return word[i:] + word[:i] + 'ay'
    # if there is no aeiouy or word is not alphabetic, raise an error
    raise TranslationError(word)    

def run():
    commands = { "-h" : print_help, 
                 "-x" : exit }
    print_title()
    while True:
        inp = raw_input(":: ").strip().lower()
        if inp in commands:
            commands[inp]()
        else:
            try:
                translation = ' '.join(map(translate, inp.split(' '))).upper()
                print("-> " + translation + "\n")
            except TranslationError as e:
                print("   Unable to translate:" + e.value + ".\n")
\$\endgroup\$
2
\$\begingroup\$

Firstly there is an error in your program.

while temp[0] not in (vowels + "y"):
    temp = temp[1:] + temp[0]

If the word entered did not have any vowels then what? It is an infinite loop in that case.

Now starting with your functions. You can use a triple quoted strings in the print_help function. It can be made like this. That way if you needed to change something you can do that without adding any other function call. Also it is clearer this way. The same for print_title() function.

def print_help():
    print(
        """
--------------------------------
 Command   |  Description
--------------------------------
 -h        |  Print help list
 -x        |  Exit program
--------------------------------
"""
          )

About the choice of your variable names, don't use string and input. They are too general. Actually input is a function in Python so using that variable you made that function unusable. That is really bad. If you want such names use an underscore after there names. That may take out the problems of accidentally using in-built keywords.

Other than that I think this is good. Calling functions by using dictionary to store their values. I learnt something.

EDIT

You are using built += " " in your function. This adds a whitespace at the end. The problem with that is that it adds a whitespace at the end of complete string also. I mean after the last word there is an extra whitespace. So you should use

built = built[0].upper() + built[1:-1]

to remove that extra whitespace.

\$\endgroup\$
  • \$\begingroup\$ A docstring is a string at the start of a function/module/etc. that describes it. What you are talking about is called a triple-quoted string. \$\endgroup\$ – Stuart Aug 26 '13 at 9:47
  • \$\begingroup\$ @Stuart My bad. I used the wrong term. I edited that. \$\endgroup\$ – Aseem Bansal Aug 26 '13 at 9:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.