0

The goal of this program is to encrypt a string. The rule is that every vowel in the string should be swapped to the third vowel after the original. If the vowel is beyond the length, return to the first one and keep counting. As for the consonants, it's similar to the first rule, except that it will be swapped to the second consonant after the original one. If there's a blank space, leave it blank.

I've encountered a problem that the string index is out of range, and I can't find where the problem is. Also, is it possible that the program is able to escape the loop automatically after text[x] can no longer find any elements?

empty=''
UA="AEIOU"
UC="BCDFGHJKLMNPQRSTVWXYZ"
text=str(input())
Flag=True
x=0

while Flag:
    if ord(text[x])==32:
        r=' '
        empty=empty+r
    elif 41<=ord(text[x])<=90:
        if (ord(text[x])==65 and ord(text[x])==69 and ord(text[x])==73 and ord(text[x])==79 and ord(text[x])==85):
            r=0
            while (ord(text[x])!=ord(UA[r])):
                r=r+1
            if r+3>=len(UA): 
                r=r-2
            else:
                r=r+3
            empty=empty+UA[r]
            x=x+1
        else:
            r=0
            while (ord(text[x])!=ord(UC[r])):
                r=r+1
            if r+2>=len(UC): 
                r=r-19
            else:
                r=r+2
            empty=empty+UC[r]
            x=x+1

    elif ord(text[x])==None:
        Flag=False
print(empty)
NULL
  • 21
  • 4
  • please check the formatting of the code. – Vardhman Patil Dec 25 '17 at 10:43
  • 1
    at what line you are getting error? – Vardhman Patil Dec 25 '17 at 10:46
  • Difficult without an exact error message and I can't reproduce the error - the last `elif` is not connected to any `if`. But many `index out of range` errors arise, because people forget that the index starts at `0`, not at `1`. – Mr. T Dec 25 '17 at 10:59
  • Oh, and for repetitive cycles, you can use the modulo operator `%` like in `(r + 3) % len(UA)` https://stackoverflow.com/a/4432235/8881141 – Mr. T Dec 25 '17 at 11:12

3 Answers3

1

While Achilleas' second solution is perfectly fine, I'd like to suggest a small extension. Instead of generating a lookup dictionary, you can use string.maketrans() and string.translate() to do the same (possibly more efficient):

# as suggested by Achilleas, define a second string by rotating the original:
vowels = "aeiou"
shifted_vowels = vowels[2:]+vowels[:2]

# create a translation table
import string
t = string.maketrans(vowels, shifted_vowels)

# apply translation table
>>> text = "i am text that is going to be altered"
>>> string.translate(text, t)
'u im toxt thit us gaung ta bo iltorod'

# or equivalently
>>> text.translate(t)
'u im toxt thit us gaung ta bo iltorod'

Look, ma, no (explicit) loops!

Pavel
  • 7,436
  • 2
  • 29
  • 42
0

I think it is very confusing to debug this code with all the for loops and all the if clauses. That is why you should try to avoid them as much as you can in python.

A good way to solve this problem is by using dictionaries to map the translations. For example for the vowels you can use the following one

vowels = {"a": "i", "e": "o", "i": "u", "o": "a", "u": "e"}

Then you can use the map funtion to map the letters of the text you want to the corresponding new value

text = "i am text that is going to be altered"
text = map(lambda x: vowels[x] if x in "aeiou" else x, text)
print("".join(text))

What the above code does is changing every x that is a vowel into its new value. Map returns a list so in the end you have to join it into a string.

The downside of this method is that you have to specify every value pair for all the letters but this is something that you can also make using a new function and reduce the point of failures in your code. This way you don't mix the translation of the word with the producing of the proper translation which makes it easier to read and debug

Edit: A nice way to do the mapping is by shifting the string of all the vowels by N ammount of spaces and the create the mapping dictionary, eg:

vowels_translation = {}
vowels = "aeiou"
shifted_vowels = vowels[2:]+vowels[:2]

for k,v in zip(vowels,shifted_vowels):
    vowels_translation[k] = v
Achilleas
  • 36
  • 1
  • 4
0

You can try this:

from string import ascii_lowercase as l
cons = filter(lambda x:x not in 'aeiou', l)
vs = 'aeiou'
text = "i am text that is going to be altered"
final_text = ''.join([i if i == ' ' else (lambda x:cons[cons.index(x)+2] if cons.index(x)+2 < len(cons) else 'b')(i) if i in cons else (lambda x:vs[vs.index(x)+3] if vs.index(x)+3 < len(vs) else 'a')(i) for i in text])

Output:

'a op wuzw wkow av jaaqj wa du onwutug'
Ajax1234
  • 69,937
  • 8
  • 61
  • 102