Permutation(swapping binary using a key order) - python

What I want is to reorder this '01110100' by a key 41325768 ,
the expected result: 11100010 , code result:10110010.
def perm(block, key):
block = list(block)
key = list(map(int, str(key))) # converting key to list
key = [x - 1 for x in key] # subtracting 1 from each (zero based)
new_key = [key[i] for i in key]
block = [block[i] for i in new_key]
block = "".join(block)
return block
so I added this line new_key = [key[i] for i in key] to fix the issue but the result so close:11100100
No idea what to do to fix it...😥

The difference between what you want and what you have is the difference in interpretation of the key. For example regarding the "4" at the start of your key, you want that to mean "put the first character in 4th position" but it's being used to say "take the first character from the fourth position".
You can change to the intended action by
def perm(block, key):
new_block = [" "]*len(key)
for ix, kval in enumerate(key):
new_block[int(kval)-1] = block[ix]
return "".join(new_block)
keyc = input('Permutation key: ')
plain = input('String to encode: ')
print ('\nResult: ', perm(str(plain),str(keyc)))
Input/output:
Permutation key: 41325768
String to encode: 01110100
Result: 11100010

I think I understood what means but your approach is wrong, here is a simple version of your code I made.
bi_s = '01110100'
key_s = '41325768'
new_bi = ''
bi_list = list(map(int, str(bi_s)))
key_list = list(map(int, str(key_s)))
print("The New Key")
for i in key_list:
# print(bi_list[i-1], end='', flush=True)
new_bi += str(bi_list[i-1])
print(new_bi)
print("The Origin Key")
for i in bi_list:
print(i, end='', flush=True)
the output :
The New Key
10110010
The Origin Key
01110100

Related

How to replace a char from an arraylist to a string? [duplicate]

This question already has answers here:
Caesar Cipher Function in Python
(27 answers)
Closed 5 months ago.
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?."
list = []
msg = 'Hello World'
key = input()
key = int(key)
print(alphabet[key])
for x in msg:
list.append(x)
print(list)
So basically i need to replace each letter of my array to a specify position (given by the key) of my string.
e.g. key = 3 so H becomes L , E becomes I , L becomes P etc...
it's basically a Caesar cipher
from collections import deque
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?. "
msg = 'Hello World'
key = int(input()) #3
new_alphabet = deque([i for i in alphabet])
new_alphabet.rotate(key)
new_message_list = [new_alphabet[alphabet.index(m)] for m in msg]
print("".join(new_message_list)) # Ebiil!Tloia
Hello, maybe one of these 2 Solutions will help you:
# Solution 1 using the ASCII table as base:
msg = 'Hello World'
key = int(input())
res = ''
for letter in msg:
res += ''.join(chr(ord(letter) + key)) # ord(letter) gets the ascii value of the letter. then adding the key and chr() trandforming back from ascii value to character
print(res)
# Solution 2 using your alphabet as base
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?."
msg = 'Hello World'
key = int(input())
res = ''
for letter in msg:
try:
position = alphabet.index(letter) + key # get the index position of each letter and adding the key
char_new = alphabet[position]
except ValueError: # handels cases where characters are used, that are not defined in alphabet
char_new = ' '
res += ''.join(char_new) # joins the new position to the result
print(res)
a space has been added to the end of alphabet to handle spaces in input.
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!?. "
lst = []
msg = 'Hello World'
key = int(input('enter key number: '))
for x in msg:
lst.append(alphabet[(alphabet.index(x) + key) % len(alphabet)])
print(''.join(lst))
import string
alphabet=[i for i in string.ascii_uppercase]
key=int(input("Enter key: "))
msg=input("Enter plain text message:").upper()
enc=[]
for i in msg:
if i == " " or i in string.punctuation:
enc.append(i)
if i in alphabet:
enc.append(alphabet[(alphabet.index(i)+key)%len(alphabet)])
print("Encrypted message is:"+"".join(enc))

Python dictionary is ordered alphabetically - how do I order it chronologically?

I'm following a tutorial (uploaded oct. 2020) about web scraping and storing the data in a dictionary. Everything works fine except the data in my dictionary starts with the newest entry and ends with the first one.
Should: {title,........, budget}
Is: {budget,........, title}
What could be the resaon for this to happen?
Part of the code:
def get_content_value(row_data):
if row_data.find("li"):
return [li.get_text(" ", strip = True).replace("\xa0", " ") for li in row_data.find_all("li")]
else:
return row_data.get_text(" ", strip = True).replace("\xa0", " ")
movie_info = {}
for index, row in enumerate(info_rows):
if index == 0:
movie_info['title'] = row.find("th").get_text(" ", strip = True)
elif index == 1:
continue
else:
content_key = row.find("th").get_text(" ", strip = True)
content_value = get_content_value(row.find("td"))
movie_info[content_key] = content_value
movie_info
index == 0 is the title
index == 1 is a picture i don't want to have
EDIT:
It's not reversed, it's in alphabetical order! Why? And how can i change it to chronological order?
Dictionaries are inherently not sorted/ordered. This is unlike lists and tuples that are ordered. To get around this issue, the collections library has OrderedDict.
You can use something like this:
# Import the OrderedDict object from `collections`
from collections import OrderedDict
def get_content_value(row_data):
if row_data.find("li"):
return [li.get_text(" ", strip = True).replace("\xa0", " ") for li in row_data.find_all("li")]
else:
return row_data.get_text(" ", strip = True).replace("\xa0", " ")
# Instead of using a regular dictionary ("{}"), we set `movie_info` to be an OrderedDict
movie_info = OrderedDict()
for index, row in enumerate(info_rows):
if index == 0:
movie_info['title'] = row.find("th").get_text(" ", strip = True)
elif index == 1:
continue
else:
content_key = row.find("th").get_text(" ", strip = True)
content_value = get_content_value(row.find("td"))
movie_info[content_key] = content_value
movie_info
It's a bit tricky, but you can do it like below.
from collections import OrderedDict
dictionary = {'one': 1, 'two': 2, 'three':3}
res = OrderedDict(reversed(list(dictionary.items())))

I get IndexError when compiling python code

I am writing a cryptosystem program in python that involves to shift left the key
I get "IndexError: string index out of range" when I compile the code.
Below is the function of left shifting
def shift_left(key):
s = ""
for i in range(1,len(key)):
print(i)
s = s + key[i]
s = s + key[0]
key = s
s = ""
return key
I added the command print(i) to know for which value of i the index is out of range
It always print 1 and 2
So the problem occurs when i = 2
I have no idea why it's out of range
def shift_left(key):
s = ""
for i in key:
print(i)
s = s + i
s = s + key[0]
key = s
s = ""
return key

Improving Encryption Algorithm

Recently I had started this assignment just meant for school purposes but I have recently decided that I would want to continue this as a new project and wanted suggestions on how I can improve my algorithm. I had an idea where I wanted the encryption key to change per character to make my encryption more secure but I have been having difficulty with this as It wouldn't work out and I couldnt decrypt my final encrypted text
Here is the encrypter:
text = input('Enter A Word : ') ##This asks a user for an input of text integers etc
encrypt = '' ##Empty Value used to store the encrypted value
temp = '' ##Empty temp value replaced at every iteration of the encryption process
temp2 =0 ##Empty temp value replaced at every iteration of the encryption process
temp_val=0
temp_char=''
rtext= text[::-1]
key=int(input('Enter your key (Your Encrypted Sentence Will Further be Encrypted Later) : '))##key used to shift the letters
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
print(hlength)
for i in range(int(hlength),len(rtext)):
##Rearranges text in a caps switch
if str.islower(rtext[i])==True:
temp=temp+str.upper(rtext[i])
elif str.isupper(rtext[i])==True:
temp=temp+str.lower(rtext[i])
else:
temp=temp+rtext[i]
for b in range(0,int(hlength)):
##Rearranges text in a caps switch
if str.islower(rtext[b])==True:
temp=temp+str.upper(rtext[b])
elif str.isupper(rtext[b])==True:
temp=temp+str.lower(rtext[b])
else:
temp=temp+rtext[b]
for j in range(0,len(temp)):
temp_val=0
temp2=0
temp_val=ord(temp[j])
temp2=temp2+temp_val+int(key)
temp_char=temp_char+chr(temp2)
encrypt=temp_char
print(encrypt)
print(temp)
print(temp2)
The Decrypter:
text = input('Enter A Word : ') ##This asks a user for an input of text integers etc
decrypt = '' ##Empty Value used to store the encrypted value
order=0
characters=''
temp=''
rtext=text[::-1]
key=int(input('Enter your key (decryption) : '))##key used to shift the letters
for i in range (0,len(rtext)):
order=0
order=order+ord(rtext[i])-int(key)
characters=characters+chr(order)
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
for j in range (int(hlength),len(characters)):
if str.islower(characters[j])==True:
temp=temp+str.upper(characters[j])
elif str.isupper(characters[j])==True:
temp=temp+str.lower(characters[j])
else:
temp=temp+characters[j]
for b in range (0,int(hlength)):
if str.islower(characters[b])==True:
temp=temp+str.upper(characters[b])
elif str.isupper(characters[b])==True:
temp=temp+str.lower(characters[b])
else:
temp=temp+characters[b]
print(temp)
I specifically want to change the variable key.
ord() - Turns characters into its Ascii equivalent
chr() - Turns Ascii numbers into its character equivalent
rtext - gets the inverse of the users input
If we simplify the code in the encryptor a little, we get:
def encrypt_text(text: str, key: int):
print("TEXT:", text, "KEY:", key)
temp = ''
temp2 = 0
temp_val = 0
temp_char = ''
rtext = text[::-1]
print("RTEXT:", rtext)
hlength = len(rtext) // 2 + len(rtext) % 2 # half, round up
print("HLENGTH:", hlength)
for i in range(hlength, len(rtext)):
# Rearrange text in a caps switch
if rtext[i].islower():
temp += rtext[i].upper()
elif rtext[i].isupper():
temp += rtext[i].lower()
else:
temp += rtext[i]
print("TEMP:", temp)
for b in range(0, int(hlength)):
# Rearrange text in a caps switch
if rtext[b].islower():
temp += rtext[b].upper()
elif rtext[b].isupper():
temp += rtext[b].lower()
else:
temp += rtext[b]
for j in range(len(temp)):
temp_val = 0
temp2 = 0
temp_val = ord(temp[j])
temp2 = temp2 + temp_val + int(key)
temp_char = temp_char + chr(temp2)
encrypt = temp_char
print("ENCRYPT:", encrypt)
print("TEMP:", temp)
print("TEMP2:", temp2)
return encrypt
text = "hello world"
key = 42
print("ENCRYPTED:", encrypt_text(text, key))
I've put it inside a function (and added some print statements), so it becomes easier to work with while developing. The code is essentially the same as yours, except
for a in range (0,len(rtext)):
if len(rtext) % 2==0:
hlength=len(rtext)/2
else:
hlength=(len(rtext)+1)/2
is replaced by
hlength = len(rtext) // 2 + len(rtext) % 2 # half, round up
which gives the same result (except hlength is an integer).
Your first two for loops do the same operation (switches case on a string). We can write a function for that:
def swap_case(str):
res = ''
for ch in str:
if ch.islower():
res += ch.upper()
elif ch.isupper():
res += ch.lower()
else:
res += ch
return res
and now we can replace the first two for loops with calls to our function:
temp += swap_case(rtext[hlength:len(rtext)]) # or shorter rtext[hlength:]
temp += swap_case(rtext[0:hlength]) # or shorter rtext[:hlength]
it just happend that .swapcase() is already a string method, so we didn't really need our swap_case function, and could just write:
temp += rtext[hlength:].swapcase()
temp += rtext[:hlength].swapcase()
Your third for-loop:
for j in range(len(temp)):
temp_val = 0 # this value is not used (it's overwritten 2 lines down)
temp2 = 0
temp_val = ord(temp[j])
temp2 = temp2 + temp_val + int(key) # temp2 is always zero at this point
temp_char = temp_char + chr(temp2)
encrypt = temp_char
can be simplified to (the initial value of temp_char is set to the empty string above):
for j in range(len(temp)): # for each index position (j)
temp_val = ord(temp[j]) # use the character at from temp at index j
temp2 = temp_val + int(key) # key is already an int from your: key=int(input('Enter your key (decryption) : '))
temp_char += chr(temp2)
encrypt = temp_char # hmm... just overwriting encrypt on every iteration
the comments mean that it could be even simpler:
encrypt = ''
for character in temp:
temp_val = ord(character)
temp2 = temp_val + key
encrypt += chr(temp2)
This leaves us with (the comments enumerate the steps taken):
def encrypt_text(text: str, key: int):
temp = ''
rtext = text[::-1] # (1) reverse the string
hlength = len(rtext) // 2 + len(rtext) % 2 # (2) split the string on hlength
second_part = rtext[hlength:].swapcase() # .. and swap case on the parts
first_part = rtext[:hlength].swapcase()
temp += second_part # (3) and put the second part..
temp += first_part # .. before the first part
encrypt = ''
for character in temp:
temp_val = ord(character)
temp2 = temp_val + key # (4) add key to every character
encrypt += chr(temp2)
return encrypt
to decrypt a string encrypted with this function, we need to do the operations "backwards and opposite":
def decrypt_text(encrypted, key):
temp = ''
for ch in encrypted:
temp += chr(ord(ch) - key) # subtract key from every character (4)
hlength = len(encrypted) // 2 + len(encrypted) % 2
half = len(encrypted) - hlength # the split point is a mirror image of what it is in encrypt_text (3)
rtext = ''
rtext += temp[half:].swapcase() # re-assemble the string and swap case (2)
rtext += temp[:half].swapcase()
text = rtext[::-1] # finally reverse (1)
return text
The standard way of using longer keys (similar to your one-key-per-character), is to use the xor function, which in Python is written as ^ (pronounced either 'hat' or 'xor'), as in:
a ^ b # true if either a, or b are true, but not both
Here is some background on how it works, although you don't really need to understand this to use it...
This operator work on bits. To see what is happening, lets define a
function to print the bit representation of an integer (you don't need
to understand this):
def bits(n):
return bin(n)[2:].zfill(4)
then we have we can show the bit patterns of integers 5 and 9, and the
operation 5 ^ 9:
bits(5) => 0101
bits(9) => 1001
--------------------
bits(5 ^ 9) => 1100
====================
if you look at the bit patterns, there is a 1 in the result where
there is exactly one 1 in the column above, so from left to right (0 ^
1 = 1, 1 ^ 0 = 1, 0 ^ 0 = 0, and 1 ^ 1 = 0).
Knowing the above, you can verify that for any number k ^ k == 0,
and n ^ 0 == n, and therefore n ^ k ^ k == n.
The useful thing about xor is that for any number n:
n ^ key ^ key == n
ie. xor-ing the number with key, twice, gives you back the number.
Let's use this to encrypt (zip(text, key) returns one character from text and key at a time, in lock-step, until one of them is "used up"):
def encrypt_xor(text: str, key: str):
if len(key) < len(text):
# key must be longer because of how zip works..
raise ValueError("Key must be at least as long as text")
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) ^ ord(k))
return res
if you try to print(encrypt_text('hello', 'world')) you'll get gibberish printed to your screen (since the value you get by xor-ing two characters isn't necessarily printable). The cool thing about xor is that the decrypt function is exactly the same as the encrypt function, so encrypting twice gives you the original value:
text = 'hello'
key = 'world'
cipher = encrypt_xor(text, key) # encrypted text is often called cipher
print(encrypt_xor(cipher, key)) # prints 'hello'
You can use a similar structure for shift-type encryption (but without the convenience that the decrypt function is the same as the encrypt), e.g.:
def encrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) + ord(k)) # add the char from the key
return res
def decrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, key):
res += chr(ord(ch) - ord(k)) # subtract the char from the key
return res
text = 'hello'
key = 'world'
cipher = encrypt_shift(text, key)
print(decrypt_shift(cipher, key)) # prints 'hello
to avoid the unpleasantness of needing a key that is longer than the text, we can start using the key from the beginning again if there is more text left. The itertools.cycle(..) function does this for us:
import itertools
def encrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, itertools.cycle(key)):
res += chr(ord(ch) + ord(k))
return res
def decrypt_shift(text: str, key: str):
res = ''
for ch, k in zip(text, itertools.cycle(key)):
res += chr(ord(ch) - ord(k))
return res
now
text = 'hello world'
key = 'world'
cipher = encrypt_shift(text, key)
print(decrypt_shift(cipher, key)) # prints 'hello world' (not just 'hello' -- the first len(key) characters)
This can be plugged into the encrypt_text and decrypt_text functions from the other answer:
def encrypt_text(text: str, key: str): # key is now a string
temp = ''
rtext = text[::-1] # (1) reverse the string
hlength = len(rtext) // 2 + len(rtext) % 2 # (2) split the string on hlength
second_part = rtext[hlength:].swapcase() # .. and swap case on the parts
first_part = rtext[:hlength].swapcase()
temp += second_part # (3) and put the second part..
temp += first_part # .. before the first part
encrypt = encrypt_shift(temp, key) # (4) shift each char using key
return encrypt
and
def decrypt_text(encrypted, key):
temp = decrypt_shift(encrypted, key) # unshift each char using key
hlength = len(encrypted) // 2 + len(encrypted) % 2
half = len(encrypted) - hlength # the split point is a mirror image of what it is in encrypt_text (3)
rtext = ''
rtext += temp[half:].swapcase() # re-assemble the string and swap case (2)
rtext += temp[:half].swapcase()
text = rtext[::-1] # finally reverse (1)
return text

itertools cycle in vigenere cipher causing problems with spaces python

In my code for vigenere cipher I use cycle from itertools to cycle through the key word. This works great until I use spaces in the message as it encrypts the space therefore making the encryption wrong. Here is the code.
message = input('enter message: ')
keyword = input('enter keyword: ')
def chr_to_int(char):
return 0 if char == 'z' else ord(char)-96
def int_to_chr(integer):
return 'z' if integer == 0 else chr(integer+96)
def add_chars(a, b):
return int_to_chr(( chr_to_int(a) + chr_to_int(b)) % 26 )
def vigenere(message, keyword):
keystream = cycle(keyword)
new = ''
for msg, key in zip(message, keystream):
if msg == ' ':
new += ' '
else:
new += add_chars(msg, key)
return new
new = vigenere(message, keyword)
print('your encrypted message is: ',new)
I think a solution to this problem would be to cycle through the space the same length of the message so it will carry on to the next letter as if the space wasn't there. I do not know how to go about how to do this .
example:
message: vignere cipher keyword: qwerty
encrypted mesasge (what it should be): mflahdib hajgvo
since cycle returns an iterable, you could instead use next instead of zip so that it only calls for the next char when asked:
>>> def vigenere(message, keyword):
keystream = cycle(keyword)
new = ''
for msg in message:
if msg == ' ':
new += ' '
else:
new += add_chars(msg, next(keystream))
return new
>>> new = vigenere('computing is fun', 'gcse')
>>> new
'jrfubwbsn ll kbq'
EDIT: per OP request, uses zip and offset variable
>>> def vigenere(message, keyword):
keystream = cycle(keyword)
new = ''
offset = 0
for msg, key in zip(message,keystream):
if msg == ' ':
new += ' '
offset += 1
else:
new += add_chars(msg, keyword[keyword.index(key)-offset])
return new
>>> new = vigenere('computing is fun', 'gcse')
>>> new
'jrfubwbsn ll kbq'

Categories

Resources