1
  • input: ['baNaNa', 7] # string and step size
  • required output : 'utGtGt' # every character of string shifted backwards by step size
import ast  
in_string = input()  
lis = ast.literal_eval(in_string)  
st = lis[0]  
step = lis[1]  
alphabets = 'abcdefghijklmnopqrstuvwxyz'  
password = ''  
for letter in st:  
    if letter in alphabets:  
        index_val = alphabets.index(letter) - (step)  
        password += alphabets[index_val]  

print(password)

Output i am getting is 'utgtgt'. I want 'utGtGt'. Help on this would be appreciated a lot.

azro
  • 53,056
  • 7
  • 34
  • 70

3 Answers3

7

The string module has methods to create a transformation dictionary and a translate method to do exactly what you want:

st = "baNaNa"
step = 7
alphabets = 'abcdefghijklmnopqrstuvwxyz'
alph2 = alphabets.upper() 

# lower case translation table
t = str.maketrans(alphabets, alphabets[-step:]+alphabets[:-step])

# upper case translation table
t2 = str.maketrans(alph2, alph2[-step:]+alph2[:-step])

# merge both translation tables
t.update(t2)

print(st.translate(t)) 

Output:

utGtGt

You give it the original string and an equal long string to map letters to and apply that dictionary using str.translate(dictionary).

The sliced strings equate to:

print(alphabets)
print(alphabets[-step:]+alphabets[:-step])

abcdefghijklmnopqrstuvwxyz
tuvwxyzabcdefghijklmnopqrs

which is what your step is for.


See Understanding slice notation if you never saw string slicing in use.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Really neat! The answer given appears to shift only lower-case characters. How would one go about shifting upper-case characters as well? (e.g. `baNaNa` to `utGtGt`, rather than `utNtNt`) – Nelewout Apr 11 '20 at 08:49
  • @saha I thought thats clear - you apply the same thing for capital letters. I edited them in as well. – Patrick Artner Apr 11 '20 at 08:53
3

by processing each charater and checking it's cardinal no and making calculation accordingly help you to reach the result

def func(string, size):
    if size%26==0:
        size=26
    else:
        size=size%26
    new_str = ''    
    for char in string:
        if char.isupper():
            if ord(char)-size<ord('A'):
                new_str+=chr(ord(char)-size+26)
            else:
                new_str+=chr(ord(char)-size)
        elif char.islower():
            if ord(char)-size<ord('a'):
                new_str+=chr(ord(char)-size+26)
            else:
                new_str+=chr(ord(char)-size)         
    return new_str


res =func('baNaNa', 7)   
print(res)

# output utGtGt
sahasrara62
  • 10,069
  • 3
  • 29
  • 44
2

Here's a simple solution that makes use of the % modulo operator to shift letters backwards.

It basically collects all of the letters in a reverse index lookup dictionary, so looking up letter positions is O(1) instead of using list.index(), which is linear O(N) lookups.

Then it goes through each letter and calculates the shift value from the letter index e.g. for the letter a with a shift value of 7, the calculation will be (0 - 7) % 26, which will give 19, the position of u.

Then once you have this shift value, convert it to uppercase or lowercase depending on the case of the original letter.

At the end we just str.join() the result list into one string. This is more efficient than doing += to join strings.

Demo:

from string import ascii_lowercase

def letter_backwards_shift(word, shift):
    letter_lookups = {letter: idx for idx, letter in enumerate(ascii_lowercase)}
    alphabet = list(letter_lookups)

    result = []
    for letter in word:
        idx = letter_lookups[letter.lower()]
        shifted_letter = alphabet[(idx - shift) % len(alphabet)]

        if letter.isupper():
            result.append(shifted_letter.upper())
        else:
            result.append(shifted_letter.lower())

    return ''.join(result)

Output:

>>> letter_backwards_shift('baNaNa', 7)
utGtGt

I would probably go with @Patrick Artner's pythonic solution. I just showed the above implementation as a learning exercise :-).

RoadRunner
  • 25,803
  • 6
  • 42
  • 75