letter shifting program in python - python

Let's say that I have a list of the alphabet:
ALPHABET = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
and lets say the shift positions are
0, 2, 19
if the input is a string
string = "xyz"
and I want to shift these 3 characters using the above shift positions of 0,2,19
as in shift 'x' 0 times to the right, shift 'y' 2 times to the right, and shift z 19 times to the right.
The only thing that comes to mind is something like the index() function of lists
I also see another problem. IF I shift 'z' 19 times to the right I will get an list index out of range error. If 'z' is shifted 19 times to the right I want it to become 's' which would be 19 shifts going around the list and starting from the beginning. Same thing with 'y' if I shift it to the right 2 times I want it to become 'a' etc....
Any suggestions on what to use?

So my way is more basic than TheSoundDefense but it works pretty well when you input three letters like "xyz". (Im guessing you can come up with a check to make sure they did so)
The main tool that i use is the index function which will match an item in the list and will give me the placement number for that item. Then I take that number and I add it to the numbers you gave. But then I divide it against the length and take the remainder. I don't care how many times it divides out to be, i just want the remainder because that tells me where its at in the alphabet. then I replace the letters and print them out.
ALPHABET = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
print "Please enter three letters"
x = list(raw_input("> ").upper())
length = len(ALPHABET)
first_letter = ALPHABET.index(x[0])
first_letter = (first_letter + 0) % length
x[0] = ALPHABET[first_letter]
second_letter = ALPHABET.index(x[1])
second_letter = (second_letter + 2) % length
x[1] = ALPHABET[second_letter]
third_letter = ALPHABET.index(x[2])
third_letter = (third_letter + 19) % length
x[2] = ALPHABET[third_letter]
print ''.join(x)

EDIT: I just realized I was probably answering a totally different question, because my brain doesn't understand the word "shift" properly. So instead of generating new letters, I'm generating an entirely new alphabet. Feel free to point and laugh.
For handling the out-of-range problem, you'll want to use the modulus function % to make the number "wrap around". You can use this in conjunction with slicing in order to get your shift.
ALPHABET = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
inputstring = "XYZ"
def shift(inputstr, shift1, shift2, shift3):
new_alphabet = list(ALPHABET)
shifts = [shift1, shift2, shift3]
for i in range(0,3):
inputchar = inputstr[i]
i1 = new_alphabet.index(inputchar)
i1_adjust = (i1 + shifts[i]) % len(new_alphabet)
temp_alphabet = new_alphabet[:i1] + new_alphabet[i1+1:]
new_alphabet = temp_alphabet[:i1_adjust] + [inputchar] + temp_alphabet[i1_adjust:]
print new_alphabet
# We call it here.
shift(inputstring,0,2,19)
We're basically finding the index of our character and adding our shift amount to it. Then we pull that character out of our alphabet and move along i1_adjust number of spaces to the new position. We pull the alphabet apart at that position, insert the character, and glue it back together. The code could probably be more elegant if shift1, shift2, shift3 was changed to a list of shift positions, but the proof of concept is there.

Can i solve this way: Let me know if you don't like this solution in comment, I will remove it. ( instead of down-voting )
#!/usr/bin/python
alpha = ['A','B','C','D','E','F','G','H','I',\
'J','K','L','M','N','O','P','Q','R',\
'S','T','U','V','W','X','Y','Z']
def shift_right(char, shift_inx):
dic1 = dict(zip(alpha, range(26)))
dic2 = dict(zip(range(26), alpha))
total = len(alpha)
nxt_inx = dic1[char] + shift_inx
if nxt_inx <= 25:
return dic2[nxt_inx]
else:
return dic2[nxt_inx % total]
def main():
for x,y in [('X', 0), ('Y', 2), ('Z', 19)]:
print '%s => %s => %s' % ( x, y, shift_right(x, y))
if __name__ == '__main__':
main()
Output:
X => 0 => X
Y => 2 => A
Z => 19 => S
OR
#!/usr/bin/python
alpha = ['A','B','C','D','E','F','G','H','I',\
'J','K','L','M','N','O','P','Q','R',\
'S','T','U','V','W','X','Y','Z']
def shift_right(char, shift_inx):
total = len(alpha)
nxt_inx = alpha.index(char) + shift_inx
if nxt_inx <= 25:
return alpha[nxt_inx]
else:
return alpha[nxt_inx % total]
def main():
for x,y in [('X', 0), ('Y', 2), ('Z', 20)]:
print '%s => %s => %s' % ( x, y, shift_right(x, y))
if __name__ == '__main__':
main()

Related

How to start again at the beginning of the word?

To apply a Vigenere coding, we have to shift the letters but not all by the same number. The key is this time a keyword which each letter gives us the shift to be done (taking A for a shift of 0, B for a shift of 1 ...).
Let's take an example to explain the method: Let's imagine that the keyword is "MATHS" and the word to code is "PYTHON".
To code P, I shift the number corresponding to M, i.e. 12 (because we start at 0 with A) which gives me B as coding for P.
Let's move on to Y: I shift it by the number corresponding to A, i.e. 0, so Y is the coding for Y here.
Let's go to T which is shifted by the number corresponding to T, i.e. 19, so T becomes M once shifted
And so on.
import string
def vigenere_cipher(msg, shift):
encrypted = ''
for i,j in zip(msg,shift):
new_index = ( string.ascii_uppercase.index(i) + string.ascii_uppercase.index(j) ) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
If our keyword is too short we start again at the beginning of the word, i.e. N will be shifted by the number corresponding to M.
My problem right here is actually with the last part, How I can simply say that if the keyword is too short we start again at the beginning of the word ?
Because only "PYTH" part is encrypted to "BYMO" with MATH as a key but not the "ON"
I think the main issue here is that you're zipping both msg and shift together, when you don't actually need to do so. You already understand the concept of using % to guarantee that you stay on a number smaller than your max number, so I'll modify your function to also use % to select which character from shift you want to use
import string
def vigenere_cipher(msg, shift):
encrypted = ''
shift_length = len(shift)
for i, char in enumerate(msg):
new_index = ( string.ascii_uppercase.index(char) + string.ascii_uppercase.index(shift[i % shift_length]) ) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
Just add the line shift = shift * (len(msg) // len(shift) + 1) at the start of the function so shift is repeated until it's longer than msg (e.g. this line turns MATH into MATHMATH)
import string
def vigenere_cipher(msg, shift):
shift = shift * (len(msg) // len(shift) + 1)
encrypted = ''
for i,j in zip(msg,shift):
new_index = (string.ascii_uppercase.index(i) + string.ascii_uppercase.index(j)) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
Output: BYMOAN

Is there any way to convert the string back to previous one?

The Question Description:
You write all your passwords in a diary so that you don't forget them. But clearly, this is too risky, so you came up with a simple plan, you will simply write it by shifting all the alphabets by a certain step. For eg: if you decide your step to be 3, then 'a' will become 'd', and 'k' will become 'n' and so for all alphabets. The last alphabets will simply circle back to 'a'. In this case, 'y' will become 'b' and so on. Now you just have to remember the step size, can then you can check the password anytime you want.
Input:
A list of two elements.
The first element will be a string consisting of only alphabets that are taken from the diary and the second element will be the step size.
Output:
A string denoting the password
Sample input: ['ytLvei', 4]
Sample output: upHrae
Explanation:
The password was 'upHrae'. Upon changing it by step of 4,
u became y,
p became t,
H became L,
r became v,
a became e,
e became i,
and thus what was written in the diary was ytKveh
Sample input: ['banana', 7]
Sample output: utgtgt
To get the above output I have written the code is given below.
import at
n = ast.literal_eval(input())
n1 = n[0]
step = n[1]
def enc_dec(string,step):
result = ''
for i in string:
temp = ''
if i=='':
result = result+i
elif i.isupper():
temp = chr((ord(i) - step - 65) % 26 + 65)
else:
temp = chr((ord(i) - step - 97) % 26 + 97)
result = result + temp
return result
print(enc_dec(n1,step))
My sample test cases i.e.
Sample input1: ['banana', 7]
Sample output2: utgtgt
Sample input2: ['ytLvei', 4]
Sample output2: upHrae
Both the above sample inputs are passing but when I try to convert the 'upHare' to 'ytLvei' I am getting another output i.e. 'qlCnwz'.
Can anyone tell me why this is happening?
This is because you are changing it up by step of 4. You need to change it down by 4. Your code doesn't work either-- you can't add and subtract ints by strs in python!
Here is a new code that should work:
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def convert_str(string, step):
converted = ""
for char in string:
if char != "Z":
converted += letters[letters.index(char) + step]
else:
converted += letters[step-1]
return converted
in_str = input("string: ")
print(convert_str(in_str, 4))
This will make upHare to ytLevi.
To convert down, use negative numbers:
print(convert_str(in_str, -4))
The cipher as described rotates the alphabet in one direction to encode, and another to decode; they aren't interchangeable operations. If you aren't allowed to specify a negative step when testing your input, then define different functions for encoding/decoding:
def encode(message: str, step: int) -> str:
return enc_dec(message, step)
def decode(message: str, step: int) -> str:
return enc_dec(message, -step)
Now you can do:
>>> print(decode('upHrae', 4))
ytLvei
This should work even when the cases are different lower or higher
import ast
n = ast.literal_eval(input())
string = n[0]
step = n[1]
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
l1='abcdefghijklmnopqrstuvwxyz'
l2='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
converted = ""
def convert_str(string, step):
converted = ""
for char in string:
if char.islower():
converted += l1[l1.index(char) + step]
elif char.isupper():
converted += l2[l2.index(char) + step]
elif char != "Z":
converted += letters[letters.index(char) + step]
print(converted)
else:
converted += letters[step-1]
return converted
print(convert_str(string, -step))

How can I optimize this function which is related to reversal of string?

I have a string: "String"
The first thing you do is reverse it: "gnirtS"
Then you will take the string from the 1st position and reverse it again: "gStrin"
Then you will take the string from the 2nd position and reverse it again: "gSnirt"
Then you will take the string from the 3rd position and reverse it again: "gSntri"
Continue this pattern until you have done every single position, and then you will return the string you have created. For this particular string, you would return: "gSntir"
And I have to repeat this entire procedure for x times where the string and x can be very big . (million or billion)
My code is working fine for small strings but it's giving timeout error for very long strings.
def string_func(s,x):
def reversal(st):
n1=len(st)
for i in range(0,n1):
st=st[0:i]+st[i:n1][::-1]
return st
for i in range(0,x):
s=reversal(s)
return s
This linear implementation could point you in the right direction:
from collections import deque
from itertools import cycle
def special_reverse(s):
d, res = deque(s), []
ops = cycle((d.pop, d.popleft))
while d:
res.append(next(ops)())
return ''.join(res)
You can recognize the slice patterns in the following examples:
>>> special_reverse('123456')
'615243'
>>> special_reverse('1234567')
'7162534'
This works too:
my_string = "String"
my_string_len = len(my_string)
result = ""
for i in range(my_string_len):
my_string = my_string[::-1]
result += my_string[0]
my_string = my_string[1:]
print(result)
And this, though it looks spaghetti :D
s = "String"
lenn = len(s)
resultStringList = []
first_half = list(s[0:int(len(s) / 2)])
second_half = None
middle = None
if lenn % 2 == 0:
second_half = list(s[int(len(s) / 2) : len(s)][::-1])
else:
second_half = list(s[int(len(s) / 2) + 1 : len(s)][::-1])
middle = s[int(len(s) / 2)]
lenn -= 1
for k in range(int(lenn / 2)):
print(k)
resultStringList.append(second_half.pop(0))
resultStringList.append(first_half.pop(0))
if middle != None:
resultStringList.append(middle)
print(''.join(resultStringList))
From the pattern of the original string and the result I constructed this algorithm. It has minimal number of operations.
str = 'Strings'
lens = len(str)
lensh = int(lens/2)
nstr = ''
for i in range(lensh):
nstr = nstr + str[lens - i - 1] + str[i]
if ((lens % 2) == 1):
nstr = nstr + str[lensh]
print(nstr)
or a short version using iterator magic:
def string_func(s):
ops = (iter(reversed(s)), iter(s))
return ''.join(next(ops[i % 2]) for i in range(len(s)))
which does the right thing for me, while if you're happy using some library code, you can golf it down to:
from itertools import cycle, islice
def string_func(s):
ops = (iter(reversed(s)), iter(s))
return ''.join(map(next, islice(cycle(ops), len(s))))
my original version takes 80microseconds for a 512 character string, this updated version takes 32µs, while your version took 290µs and schwobaseggl's solution is about 75µs.
I've had a play in Cython and I can get runtime down to ~0.5µs. Measuring this under perf_event_open I can see my CPU is retiring ~8 instructions per character, which seems pretty good, while a hard-coded loop in C gets this down to ~4.5 instructions per ASCII char. These don't seem to be very "Pythonic" solutions so I'll leave them out of this answer. But included this paragraph to show that the OP has options to make things faster, and that running this a billion times on a string consisting of ~500 characters will still take hundreds of seconds even with relatively careful C code.

python intelligent hexadecimal numbers generator

I want to be able to generate 12 character long chain, of hexadecimal, BUT with no more than 2 identical numbers duplicate in the chain: 00 and not 000
Because, I know how to generate ALL possibilites, including 00000000000 to FFFFFFFFFFF, but I know that I won't use all those values, and because the size of the file generated with ALL possibilities is many GB long, I want to reduce the size by avoiding the not useful generated chains.
So my goal is to have results like 00A300BF8911 and not like 000300BF8911
Could you please help me to do so?
Many thanks in advance!
if you picked the same one twice, remove it from the choices for a round:
import random
hex_digits = set('0123456789ABCDEF')
result = ""
pick_from = hex_digits
for digit in range(12):
cur_digit = random.sample(hex_digits, 1)[0]
result += cur_digit
if result[-1] == cur_digit:
pick_from = hex_digits - set(cur_digit)
else:
pick_from = hex_digits
print(result)
Since the title mentions generators. Here's the above as a generator:
import random
hex_digits = set('0123456789ABCDEF')
def hexGen():
while True:
result = ""
pick_from = hex_digits
for digit in range(12):
cur_digit = random.sample(hex_digits, 1)[0]
result += cur_digit
if result[-1] == cur_digit:
pick_from = hex_digits - set(cur_digit)
else:
pick_from = hex_digits
yield result
my_hex_gen = hexGen()
counter = 0
for result in my_hex_gen:
print(result)
counter += 1
if counter > 10:
break
Results:
1ECC6A83EB14
D0897DE15E81
9C3E9028B0DE
CE74A2674AF0
9ECBD32C003D
0DF2E5DAC0FB
31C48E691C96
F33AAC2C2052
CD4CEDADD54D
40A329FF6E25
5F5D71F823A4
You could also change the while true loop to only produce a certain number of these based on a number passed into the function.
I interpret this question as, "I want to construct a rainbow table by iterating through all strings that have the following qualities. The string has a length of 12, contains only the characters 0-9 and A-F, and it never has the same character appearing three times in a row."
def iter_all_strings_without_triplicates(size, last_two_digits = (None, None)):
a,b = last_two_digits
if size == 0:
yield ""
else:
for c in "0123456789ABCDEF":
if a == b == c:
continue
else:
for rest in iter_all_strings_without_triplicates(size-1, (b,c)):
yield c + rest
for s in iter_all_strings_without_triplicates(12):
print(s)
Result:
001001001001
001001001002
001001001003
001001001004
001001001005
001001001006
001001001007
001001001008
001001001009
00100100100A
00100100100B
00100100100C
00100100100D
00100100100E
00100100100F
001001001010
001001001011
...
Note that there will be several hundred terabytes' worth of values outputted, so you aren't saving much room compared to just saving every single string, triplicates or not.
import string, random
source = string.hexdigits[:16]
result = ''
while len(result) < 12 :
idx = random.randint(0,len(source))
if len(result) < 3 or result[-1] != result[-2] or result[-1] != source[idx] :
result += source[idx]
You could extract a random sequence from a list of twice each hexadecimal digits:
digits = list('1234567890ABCDEF') * 2
random.shuffle(digits)
hex_number = ''.join(digits[:12])
If you wanted to allow shorter sequences, you could randomize that too, and left fill the blanks with zeros.
import random
digits = list('1234567890ABCDEF') * 2
random.shuffle(digits)
num_digits = random.randrange(3, 13)
hex_number = ''.join(['0'] * (12-num_digits)) + ''.join(digits[:num_digits])
print(hex_number)
You could use a generator iterating a window over the strings your current implementation yields. Sth. like (hex_str[i:i + 3] for i in range(len(hex_str) - window_size + 1)) Using len and set you could count the number of different characters in the slice. Although in your example it might be easier to just compare all 3 characters.
You can create an array from 0 to 255, and use random.sample with your list to get your list

Three Rail Decrypt [duplicate]

This question already has an answer here:
Three Rail Decrypt when rails are different lengths
(1 answer)
Closed 8 years ago.
Im having a ton of trouble trying to figure out how to get my decrypt function to work. It works in ideal cases where the msg is divisible by 3, but after that i am totally lost. I have a vague idea of what i have to do because i was able to get this to work with two rails, but there are more possibilities with three rails. Im quite lost :( Also all those print statements are just to try and help me figure out what is going on within my program.
import sys
def main():
plaintext="abcdefgh"
print(threeRailEncrypt(plaintext))
print(threeRailDecrypt(threeRailEncrypt(plaintext)))
def threeRailEncrypt(plaintext):
ciphertext=""
rail1=""
rail2=""
rail3=""
for i in range(len(plaintext)):
if i%3 == 0:
rail1=rail1+plaintext[i]
elif i%3 == 1:
rail2=rail2+plaintext[i]
else:
rail3=rail3+plaintext[i]
ciphertext=rail1+rail2+rail3
return(ciphertext)
def threeRailDecrypt(msg):
if len(msg)%3==0:
third=len(msg)//3
print(third)
rail1=msg[:third]
rail2=msg[third:third*2]
rail3=msg[third*2:]
print(rail1,rail2,rail3)
dm=""
for i in range(third):
dm=dm+rail1[i]
dm=dm+rail2[i]
dm=dm+rail3[i]
else:
third=(len(msg)//3)+1
print(third)
rail1=msg[:third]
rail2=msg[third:third*2]
rail3=msg[third*2:]
print(rail1,rail2,rail3)
dm=""
for i in range(third):
dm=dm+rail1[i]
print(dm)
dm=dm+rail2[i]
print(dm)
dm=dm+rail3[i]
print(dm)
if len(rail2)>len(rail3):
dm=dm+rail2[-1]
return(dm)
main()
Progress-
def threeRailDecrypt(cypher, rails = 3):
length = len (cypher)
for i in range(rails):
lens=(length//rails)
if length % rails > i:
lens=lens+1
print(lens)
I will add a second answer with a completely different approach and more explicit code:
def dec2 (cypher):
length = len (cypher)
if length < 4: return cypher
third = length // 3 + (1 if length % 3 else 0)
cypher = list (cypher)
if length % 3 == 1: cypher.insert (third * 2 - 1, '')
return ''.join (''.join (cypher [i::third] ) for i in range (third) )
Or just shock your teacher:
enc = lambda p:''.join(p[_::3]for _ in range(3))
dec = lambda c:c if len(c)<4 else(lambda *a:(lambda c,t:
''.join(''.join(c[i::t])for i in range(t)))((lambda c,t,
l:c[:t*2-1]+(['']if l%3==1 else[])+c[t*2-1:])(*a),a [2])
)(*(lambda c:(list(c),len(c),len(c)//3+(1 if len(c)%3
else 0)))(c))
New:
You just have to split up the strings again as you did in your encryption function and then iterate over them to put each character back at it's real place.
def decrypt(crypt):
rails = []
result = ""
rails.append(crypt[:(len(crypt)+2)/3])
rails.append(crypt[(len(crypt)+2)/3:-(len(crypt)-2)/3])
rails.append(crypt[-(len(crypt)/3):])
for x in range(len(crypt)):
result += rails[x%3][:1]
rails[x%3] = rails[x%3][1:]
return(result)
I think Hyperboreus second solution is cooler though!
OLD(Interesting thought connected to the comments, didn't work as expected for longer strings though):
You will just have to reverse what you do in the encryption, so in the encryption you scramble the text by splitting them up with modulo 3. The simplest way to get the plaintext back again is to simply run the encryption method the length of the string minus two times on the encrypted string and it will be back to plain text.
def threeRailDecrypt(crypt):
for i in range(len(crypt)-2):
crypt = threeRailEncrypt(crypt)
return(crypt)
Hyperboreus solution is the proper one, but this is a bit simpler to understand I reckon.
Example with the string test:
test - untouched
ttes - first iteration (encryption)
tste - second iteration
test - third iteration
This should work. You just need to figure out how long the different rails are:
from itertools import zip_longest as zip
def enc (plain, rails = 3):
return ''.join (plain [i::rails] for i in range (rails) )
def dec (cypher, rails = 3):
length = len (cypher)
lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]
return ''.join (''.join (x for x in x if x) for x in zip (*paths) )
plain = 'abcdefghijk'
for i in range (10):
a = plain [:i]
b = enc (a)
c = dec (b)
print (a, b, c)
Should work for arbitrary (>0) number of rails used.
EDIT: Without zip_longest:
def enc (plain, rails = 3):
return ''.join (plain [i::rails] for i in range (rails) )
def dec (cypher, rails = 3):
length = len (cypher)
lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
paths = [cypher [sum (lens [:i]):sum (lens [:i + 1] ) ] for i in range (rails) ]
maxLen = len (paths [0] )
paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]
return ''.join (''.join (x) for x in zip (*paths) )
Explanation of the decryption:
length = len (cypher)
Store the length of the cypher text in a local variable for convenience.
lens = [length // rails + (1 if length % rails > i else 0) for i in range (rails) ]
Now we calculate the length of each rail. The length of each rail is the length of the cypher text divided by the number of rails (in your case 3), and maybe (the if part) plus 1 if the length is not exactly divisible.
paths = [cypher [sum (lens [:i] ):sum (lens [:i + 1] ) ] for i in range (rails) ]
Now slice the cypher text into the different rails, according to the rail lengths we have just calculated.
maxLen = len (paths [0] )
The maximum length of a rail is equal to the length of the first rail.
paths = [list (path) + ( [] if len (path) == maxLen else [''] ) for path in paths]
Now add an empty character to the end of each rail which is too short, so all rails have the same length and can be zipped.
return ''.join (''.join (x) for x in zip (*paths) )
Zip the rails, join each resulting tuple into a string, then join all those strings into one long string and return it.

Categories