I need help reversing this encoding algorithm into a decoding algorithm. I understand the swap function but I'm having trouble with rest of the code.
from string import ascii_letters, digits
def shift(text, shift: int = 0):
SPACE = ' '
letters = ascii_letters + digits + SPACE
letters_length = len(letters)
shifted_chars = []
for char in text:
if char in letters:
shifted_chars.append(letters[(letters.index(char) + shift) % letters_length])
else:
shifted_chars.append(char)
return ''.join(shifted_chars)
def swap(text):
middle = len(text) // 2
return text[middle:] + text[:middle]
def encode(text):
if len(text) < 2:
return shift(text, 7)
for i in range(31):
text = swap(shift(text, i))
return text
Fixed owing to Parisa.H.R's useful comment(s).
The deswap(text) function equalizes asymmetric result of swap(text) in case of odd len(text).
from string import ascii_letters, digits
def shift(text, shift: int = 0):
SPACE = ' '
letters = ascii_letters + digits + SPACE
letters_length = len(letters)
shifted_chars = []
for char in text:
if char in letters:
shifted_chars.append(letters[(letters.index(char) + shift) % letters_length])
else:
shifted_chars.append(char)
return ''.join(shifted_chars)
def swap(text):
middle = len(text) // 2
return text[middle:] + text[:middle]
def deswap(text):
middle = (len(text) + (len(text) % 2)) // 2
return text[middle:] + text[:middle]
def encode(text):
if len(text) < 2:
return shift(text, 7)
for i in range(31):
text = swap(shift(text, i))
return text
def decode(text):
if len(text) < 2:
return shift(text, -7)
for i in range(30, -1, -1):
text = deswap(shift(text, -i))
# text = shift(deswap(text), -i)
return text
Output:
decode(encode('opening'))
# 'opening'
decode(encode('openin'))
# 'openin'
decode(encode('Quora'))
# 'Quora'
decode(encode('Quoran'))
# 'Quoran'
decode(encode(ascii_letters + digits)) == ascii_letters + digits
# True
decode(encode(ascii_letters + digits + ' ')) == ascii_letters + digits + ' '
# True
Related
I have a school project question (for Python) that goes like this:
Given a string_input such as "abcd&1-4efg", the function must remove the "&1-4" and insert the string slice from 1 to 4 where the "&1-4" was.
eg. if string_input = "abcd&1-4efg",
"&1-4" is removed.
The remaining characters are indexed as follows: a=0, b=1, c=2, d=3, e=4, f=5, g=6
The new string becomes:
"abcdbcdeefg"
I've managed to write a long chunk of code to do this, but I'm wondering if anyone has any more efficient solutions?
Things to note:
The instructions can include double digits (eg. &10-15)
If the index isn't found, the returned string should print "?" for every missing index
(eg. "abcd&5-10efgh" would return "abcdfgh???efgh")
Intructions can be back-to-back (eg. "&10-15abcdef&1-5&4-5pqrs")
The code I've written is:
def expand(text):
text += "|"
import string
digits_dash = string.digits + "-"
idx_ref_str = ""
replace_list = []
record_val = False
output_to_list = []
instruct = ""
and_idx_mark = 0
#builds replace_list & idx_ref_list
for idx in range(len(text)):
if text[idx] == "&" and record_val==True:
output_to_list.append(instruct)
output_to_list.append(and_idx_mark)
replace_list.append(output_to_list)
output_to_list, instruct, inst_idx, and_idx_mark = [],"",0,0
and_idx_mark = idx
continue
elif text[idx] == "&":
record_val = True
and_idx_mark = idx
continue
#executes if currently in instruction part
if record_val == True:
#adds to instruct
if text[idx] in digits_dash:
instruct += text[idx]
#take info, add to replace list
else:
output_to_list.append(instruct)
output_to_list.append(and_idx_mark)
replace_list.append(output_to_list)
output_to_list, instruct, inst_idx, and_idx_mark, record_val = [],"",0,0,False
#executes otherwise
if record_val == False:
idx_ref_str += text[idx]
idx_ref_str = idx_ref_str[:-1]
text = text[:-1]
#converts str to int indexes in replace list[x][2]
for item in replace_list:
start_idx = ""
end_idx = ""
#find start idx
for char in item[0]:
if char in string.digits:
start_idx += char
elif char == "-":
start_idx = int(start_idx)
break
#find end idx
for char in item[0][::-1]:
if char in string.digits:
end_idx = char + end_idx
elif char == "-":
end_idx = int(end_idx)
break
start_end_list = [start_idx,end_idx]
item+=start_end_list
#split text into parts in list
count = 0
text_block = ""
text_block_list = []
idx_replace = 0
for char in text:
if char == "&":
text_block_list.append(text_block)
text_block = ""
count += len(replace_list[idx_replace][0])
idx_replace +=1
elif count > 0:
count -= 1
else:
text_block += char
text_block_list.append(text_block)
#creates output str
output_str = ""
for idx in range(len(text_block_list)-1):
output_str += text_block_list[idx]
#creates to_add var to add to output_str
start_repl = replace_list[idx][1]
end_repl = replace_list[idx][1] + len(replace_list[idx][0])
find_start = replace_list[idx][2]
find_end = replace_list[idx][3]
if end_idx >= len(idx_ref_str):
gap = end_idx + 1 - len(idx_ref_str)
to_add = idx_ref_str[find_start:] + "?" * gap
else:
to_add = idx_ref_str[find_start:find_end+1]
output_str += to_add
output_str += text_block_list[-1]
return output_str
Here's how I would do it. Always open to criticism.
import re
s = 'abcd&1-4efg'
c = re.compile('&[0-9]+-[0-9]+')
if (m := c.search(s)):
a, b = m.span()
left = s[:a]
right = s[b:]
o = [int(x) for x in m.group(0)[1:].split('-')]
mid = (left+right)[o[0]:o[1]+1]
print(left + mid + right)
In my sentence i want :
replace every # by *
skip every ?
if the ascii value of a char is pair so i am transforming into LowerCase + Shift Value ( input user)
if the ascii value of a char is impair so i am transforming into UpperCase + Shift Value ( input user)
Its tell me
line 19, in replace
new = ord(lower(c)) + (shift % 26)
TypeError: ord() expected string of length 1, but NoneType found
def lower(c):
if 'A' <= c <= 'Z':
c = chr(ord(c) + (ord('a') - ord('A')))
def upper(c):
if 'a' <= 'c' <= 'z':
c = chr(ord(c) - (ord('a') - ord('A')))
def replace(text):
new_text = ''
for c in text:
if c == '#':
new_text += '*'
elif c == '?':
continue
elif ord(c) % 2 == 0:
new = ord(lower(c)) + (shift % 26)
if new > ord('z'):
new = (ord('a') + (new - ord('z')))
new_text += chr(new)
elif ord(c) % 2 != 0:
new = ord(upper(c)) + (shift % 26)
if new_text > 'Z':
new_text = chr('Z' + (new_text - 'Z'))
new_text += chr(new)
return new_text
sentence = (input("Please enter a sentence to encrypt:\n"))
shift = int(input("Please enter the size of the shift:\n"))
sentence = replace(sentence)
I have some problem with my caesar code.
1) I don't know how to check if a character is a punctuation and print without sum.
2) print the char on the same line but when it's finished return a newline.
3) Iterate through the alphabet with big number return me a punctuation, how can I do to return just a character?
import sys
import string
def main():
if len(sys.argv) != 2:
print("Usage: caesar.py k")
else:
k = int(sys.argv[1])
if k == 1 or k <= 26:
text = input("plaintext: ");
j = len(text)
for i in range(j):
#check if is a character
if text[i].isalpha:
if text[i].islower():
print(chr(ord(text[i]) + k),end = "")
if text[i].isupper():
print(chr(ord(text[i]) + k),end = "")
elif text[i].punctuation():
print(text[i])
else:
print("You have to introduce a number between 1 and 26")
main()
Try this code:
import string
def encrypt_ceasar(s, shift):
assert abs(shift) < 26, 'shift is between -25 and 25 (inclusive)'
encrypted_s = ''
for char in s:
if char.isalpha():
is_upper = char.isupper()
char = char.lower()
pos_alphabet = ord(char) - ord('a')
new_pos = (pos_alphabet + shift) % 26
encryted_char = chr(ord('a') + new_pos)
if is_upper:
encryted_char = encryted_char.upper()
encrypted_s += encryted_char
else:
encrypted_s += char
return encrypted_s
def decrypt_ceasar(s, shift):
return encrypt_ceasar(s, -shift)
if __name__ == "__main__":
s = 'AbC1$de#zy'
encrypted_s = encrypt_ceasar(s, 3)
print('s:', s)
print('encrypted_s:', encrypted_s)
print('again s:', decrypt_ceasar(encrypted_s, 3))
Output:
s: AbC1$de#zy
encrypted_s: DeF1$gh#cb
again s: AbC1$de#zy
def encrypt(string, new_string):
i = 0
if i < len(string):
if ord(string[i]) > 65 and ord(string[i]) < 97:
new_string = string[i] + encrypt(string[1:], new_string)
if ord(string[i]) >= 97 or ord(string[i]) == 32:
if not(ord(string[i])) == 32:
x = ord(string[i])
x = x + 1
y = chr(x)
new_string = new_string + y
new_string = encrypt(string[1:], new_string)
else:
new_string = new_string + ' '
new_string = encrypt(string[1:], new_string)
return new_string
string = input("Enter a message: \n")
new_string = ''
print("Encrypted message:")
print(encrypt(string, new_string))
If there is more than one uppercase letter, it will output the uppercase letters at the front of the encrypted message.
For example: 'Hello World' becomes 'HWfmmp psme'. However, the output should have been 'Hfmmp Xpsme'
translate can help you to do this kind of conversion.
from string import ascii_lowercase
def encrypt(data):
transmap = str.maketrans(ascii_lowercase, ascii_lowercase[1:] + ascii_lowercase[0])
return data.translate(transmap)
value = 'Hello World'
print(encrypt(value))
The result is Hfmmp Wpsme.
It's easy to change the encrypt function to work with a flexible offset.
from string import ascii_lowercase
def encrypt(data, offset=1):
transmap = str.maketrans(ascii_lowercase, ascii_lowercase[offset:] + ascii_lowercase[0:offset])
return data.translate(transmap)
value = 'Hello World'
print(encrypt(value, offset=2))
print(encrypt(value, offset=-1))
This will print Hgnnq Wqtnf and Hdkkn Wnqkc.
>>> import re
>>> re.sub('[a-z]',lambda x:chr(ord(x.group(0))+1),'Hello World')
'Hfmmp Wpsme'
>>>
I am trying to get this python script to create a new file and continue generating word combinations once a certain file size is reached.
f=open('wordlist', 'w')
def xselections(items, n):
if n==0: yield []
else:
for i in xrange(len(items)):
for ss in xselections(items, n-1):
yield [items[i]]+ss
# Numbers = 48 - 57
# Capital = 65 - 90
# Lower = 97 - 122
numb = range(48,58)
cap = range(65,91)
low = range(97,123)
choice = 0
while int(choice) not in range(1,8):
choice = raw_input('''
1) Numbers
2) Capital Letters
3) Lowercase Letters
4) Numbers + Capital Letters
5) Numbers + Lowercase Letters
6) Numbers + Capital Letters + Lowercase Letters
7) Capital Letters + Lowercase Letters
: ''')
choice = int(choice)
poss = []
if choice == 1:
poss += numb
elif choice == 2:
poss += cap
elif choice == 3:
poss += low
elif choice == 4:
poss += numb
poss += cap
elif choice == 5:
poss += numb
poss += low
elif choice == 6:
poss += numb
poss += cap
poss += low
elif choice == 7:
poss += cap
poss += low
bigList = []
for i in poss:
bigList.append(str(chr(i)))
MIN = raw_input("What is the min size of the word? ")
MIN = int(MIN)
MAX = raw_input("What is the max size of the word? ")
MAX = int(MAX)
for i in range(MIN,MAX+1):
for s in xselections(bigList,i): f.write(''.join(s) + '\n')
You can encapsulate the file rotation behavior in a class. When you are writing some data, the write method will first check if the write would exceed the file size limit; then it calls the rotate method which closes the current file and opens a new one, incrementing the sequence number on the filename:
import os
class LimitWriter(object):
def __init__(self, basepath, bytelimit):
self._basepath = basepath
self._bytelimit = bytelimit
self._sequence = 0
self._output = None
self._bytes = 0
self._rotate()
def _rotate(self):
if self._output:
self._output.close()
path = '%s.%06d' % (self._basepath, self._sequence)
self._output = open(path, 'wb')
self._bytes = 0
self._sequence += 1
def write(self, data):
size = len(data)
if (self._bytes + size) > self._bytelimit:
self._rotate()
self._bytes += size
self._output.write(data)
out = LimitWriter('wordlist', 1024 * 1024 * 1)
for i in range(MIN,MAX+1):
for s in xselections(bigList,i):
out.write(''.join(s) + '\n')
Would output a series of files which are smaller than 1MB:
1.0M wordlist.000000
1.0M wordlist.000001
252K wordlist.000002
Update - A few more tips on using some of the built-in power of Python to help make your code a bit shorter and easier to follow. I've included comments explaining each part.
Here are the docs on the modules I use below: itertools, string.
import itertools
import os
from string import digits, lowercase, uppercase
# PUT LimitWriter CLASS DEFINITION HERE
LIMIT = 1024 * 1024 * 1
choice = 0
while int(choice) not in range(1,8):
choice = raw_input('''
1) Numbers
2) Capital Letters
3) Lowercase Letters
4) Numbers + Capital Letters
5) Numbers + Lowercase Letters
6) Numbers + Capital Letters + Lowercase Letters
7) Capital Letters + Lowercase Letters
: ''')
MIN = int(raw_input("What is the min size of the word? "))
MAX = int(raw_input("What is the max size of the word? "))
# replace your ranges and large if/else with this
choices = {
1: digits,
2: uppercase,
3: lowercase,
4: uppercase + lowercase,
5: digits + lowercase,
6: digits + uppercase + lowercase,
7: uppercase + lowercase
}
# pick one of the sets with the user's choice
chars = choices[int(choice)]
out = LimitWriter('wordlist', LIMIT)
# generate all permutations of the characters from min to max
for length in range(MIN, MAX+1):
for tmp in itertools.permutations(chars, length):
out.write(''.join(tmp) + '\n')
Here's the final working code. Change the variable mbXY inside function generate_wordlist to establish the size cap of each file provided it gets bigger than this size. This file has been updated to run under Python 3.2
import itertools
import subprocess
import os
from string import digits, ascii_lowercase, ascii_uppercase, punctuation
if os.name == 'nt':
def clear_console():
subprocess.call("cls", shell=True)
return
else:
def clear_console():
subprocess.call("clear", shell=True)
return
def generate_phone_numbers(area_code):
f = open('phones.txt', 'w')
for i in range(2010000, 9999999):
f.write(area_code + str(i) + '\n')
def generate_wordlist(lst_chars, min_digit, max_digit, lst_name):
mb1 = 1024000
mb10 = 1024000 * 10
mb100 = 1024000 * 100
mb250 = 1024000 * 250
mb500 = 1024000 * 500
gb1 = 1024000 * 1000
file_size_limit = mb10
out = file_writer(lst_name, file_size_limit)
for curr_length in range(min_digit, max_digit + 1):
for curr_digit in itertools.product(lst_chars, repeat=curr_length):
out.write(''.join(curr_digit) + '\n')
class file_writer(object):
def __init__(self, basepath, bytelimit):
self._basepath = basepath
self._bytelimit = bytelimit
self._sequence = 0
self._output = None
self._bytes = 0
self._rotate()
def _rotate(self):
if self._output:
self._output.close()
path = '%s.%06d' % (self._basepath, self._sequence)
self._output = open(path, 'wb')
self._bytes = 0
self._sequence += 1
def write(self, data):
size = len(data)
if (self._bytes + size) > self._bytelimit:
self._rotate()
self._bytes += size
self._output.write(bytes(data, "utf-8"))
choice = 0
while int(choice) not in range(1,6):
clear_console()
print ('')
print (' wgen - Menu')
choice = input('''
1. Phone numbers.
2. Numbers.
3. Numbers + Lowercase.
4. Numbers + Lowercase + Uppercase.
5. Numbers + Lowercase + Uppercase + Punctuation.
Enter Option: ''')
print ('')
choice = int(choice)
if choice == 1:
area_code = input('''
Please enter Area Code: ''')
area_code = str(area_code)
area_code = area_code.strip()
if len(area_code) == 3:
print ('')
print (' Generating phone numbers for area code ' + area_code + '.')
print (' Please wait...')
generate_phone_numbers(area_code)
if choice == 2:
min_digit = input(' Minimum digit? ')
min_digit = int(min_digit)
print ('')
max_digit = input(' Maximum digit? ')
max_digit = int(max_digit)
lst_chars = digits
lst_name = 'num'
print ('')
print (' Generating numbers between ' + str(min_digit) + ' and ' + str(max_digit) + ' digits.')
print (' Please wait...')
generate_wordlist(lst_chars, min_digit, max_digit, lst_name)
if choice == 3:
min_digit = input(' Minimum digit? ')
min_digit = int(min_digit)
print ('')
max_digit = input(' Maximum digit? ')
max_digit = int(max_digit)
lst_chars = digits + ascii_lowercase
lst_name = 'num_low'
print ('')
print (' Generating numbers & lowercase between ' + str(min_digit) + ' and ' + str(max_digit) + ' digits.')
print (' Please wait...')
generate_wordlist(lst_chars, min_digit, max_digit, lst_name)
if choice == 4:
min_digit = input(' Minimum digit? ')
min_digit = int(min_digit)
print ('')
max_digit = input(' Maximum digit? ')
max_digit = int(max_digit)
lst_chars = digits + ascii_lowercase + ascii_uppercase
lst_name = 'num_low_upp'
print ('')
print (' Generating numbers, lowercase & uppercase between ' + str(min_digit) + ' and ' + str(max_digit) + ' digits.')
print (' Please wait...')
generate_wordlist(lst_chars, min_digit, max_digit, lst_name)
if choice == 5:
min_digit = input(' Minimum digit? ')
min_digit = int(min_digit)
print ('')
max_digit = input(' Maximum digit? ')
max_digit = int(max_digit)
lst_chars = digits + ascii_lowercase + ascii_uppercase + punctuation
lst_name = 'num_low_upp_pun'
print ('')
print (' Generating numbers, lowercase, uppercase & punctuation between ' + str(min_digit) + ' and ' + str(max_digit) + ' digits.')
print (' Please wait...')
generate_wordlist(lst_chars, min_digit, max_digit, lst_name)