I'm trying to do the parity control challenge on Code Abbey. I've been having trouble with it for months, but I finally have it...almost. The output it returns is off by a few characters, and I was wondering if anyone could point me in the right direction. I'm stumped, in part because my code is so sloppy even I can't really parse it (I'll fix that).
I hope this isn't too close to homework help. I know you guys hate that.
import string
characters = string.letters + ' ' + '.' + string.digits
characters = zip(characters, [bin(ord(i))[2:] for i in characters])
nch = {}
squareseven = 128
for char in characters:
# For readability. a is the character, like A or ., b is the binary.
a = char[0]
b = char[1]
if b.count('1') % 2 != 0:
nch[a] = int(b, 2) + squareseven
else:
nch[a] = int(b, 2)
with open('input.txt', 'r') as O:
O = map(int, str(O.read()).strip().split())
decyphered = ''
for binary in O:
# If the number of ones is odd, 128 is added.
if bin(binary)[2:].count('1') % 2 != 0:
tmp = binary + squareseven
else:
tmp = binary
# Because the ASCII binaries only go up to 255.
if tmp < 256:
if tmp in nch.values():
for char, b in nch.iteritems():
if b == tmp:
decyphered += char
with open('output.txt', 'w') as output:
output.write(decyphered)
most problems can be better attacked by breaking them into smaller sub problems
first write a method to help check the data
def check_char(n):
"""return ascii code if parity check success else None"""
bits = "{0:08b}".format(n)
if int(bits[0]) == sum(map(int,bits[1:]))%2:
return n&0x7f #get rid of the parity bit when return ascii
then a method to handle a single line
def translate_line(line):
ascii_codes = map(int,line.split())
checked_values = [check_char(n) for n in ascii_codes]
return "".join(chr(val) for val in checked_values if val)
print translate_line("65 238 236 225 46")
then just loop over your lines passing them in
Related
I am trying to remake the built-in function for bin(x) for better understanding, I have got that part down, now the issue is how to dynamically remove the 0s when they are not necessary.
I have tried using replace() but it seems to be removing every suggested "0" I am unsure how to select the zeroes till it hits the first index in which there is a "1"
for eg:
if i have 0b00010010
___
0b00010010
^
I would like to select the numbers after the 0b and erase the 0s right after until "1"
def bin(x):
if x>0:
binary = ""
i = 0
while x>0 and i<=16:
string = str(int(x%2))
binary = binary+string
x/=2
i = i+1
d = binary[::-1]
ret = f"0b{d}"
return ret.replace("00","")
else:
x = abs(x)
binary = ""
i = 0
while x > 0 and i <=16:
string = str(int(x % 2))
binary = binary + string
x /= 2
i = i + 1
nd = binary[::-1]
ret = f"-0b{nd}"
return ret.replace("00","")
print(bin(8314))# 0b00010000001111010 this is the current out
0b00010000001111010 this is the current output
0b10000001111010 this is what I want
It might be better to simplify things by not generating those extra zeroes in the first place:
def bin(x):
prefix = ("-" if x < 0 else "")
x = abs(x)
bits = []
while x:
x, bit = divmod(x, 2) # division and remainder in one operation
bits.append(str(bit))
# Flip the bits so the LSB is on the right, then join as string
bit_string = ''.join(bits[::-1])
# Form the final string
return f"{prefix}0b{bit_string}"
print(bin(8314))
prints
0b10000001111010
You should take a look at lstrip():
>>> b = "00010000001111010"
>>> b.lstrip("0")
'10000001111010'
Of course, make sure to prefix the binary with "0b" after calling lstrip().
Scott Hunter brought up a nice solution to your problem, however, if you want to use a for loop, consider trying the following:
binary = "0b00010000001111010"
start_index = binary.find("b")
for index in range(b+1, len(binary)):
if binary[index] == 0:
binary = binary[0:index:] + binary[index+1::]
else:
break
I am not really familiar with Python yet.
I have a string like "11223300". Now I want to increase the last byte of that string ( from "00" to "FF"). I tried to convert the string into an integer ( integer=int(string,16)) and increase it, and convert it back later, but that does not work for me. Maybe one of you guys has a better idea.
string = "11223300"
counter = int(string, 16)
for i in range(255):
counter = counter + 1
IV = hex(counter)
Now I want to convert the IV from hex into a string
Thanks!
You can use format to convert int to your hex string, which will not keep the 0x prefix:
string = "11223300"
counter = int(string, 16)
for i in range(255):
counter = counter + 1
IV = format(counter, 'X')
print(IV)
Output:
112233FF
The function below takes a string and increases it by n from a given charset
For example, in the charset ['a','b','c'] :
"aaa" + 1 = "aab"
"aac" + 1 = "aba"
"acc" + 2 = "bab"
def str_increaser(mystr, charset, n_increase):
# Replaces a char in given string & index
def replace_chr_in_str(mystr, index, char):
mystr = list(mystr)
mystr[index] = char
return ''.join(mystr)
# Increases the char last (n) and possibly its left neighboor (n-1).
def local_increase(mystr, charset):
l_cs = len(charset)
# increasing 1 to last char if it's not the last char in charset (e.g. 'z' in lowercase ascii).
if (charset.index(mystr[-1]) < l_cs - 1):
mystr = replace_chr_in_str(mystr, -1, charset[charset.index(mystr[-1]) + 1])
# else, reset last char to the first one in charset and increase the its left char, using a reducted string for recursion
else:
mystr = replace_chr_in_str(mystr, -1, charset[0])
mystr = local_increase(mystr[:-1], charset) + mystr[-1]
return mystr
# Case if input = "zz...zz" in an ascii lowercase charset for instance
if (mystr == charset[-1] * len(mystr)):
print("str_increaser(): Input already max in charset")
else:
for i in range(n_increase):
mystr = local_increase(mystr, charset)
return mystr
Here's an exemple :
# In bash : $ man ascii
# charset = map(chr, range(97, 123)) + map(chr, range(65, 91))
import string
charset = string.lowercase + string.uppercase
print(str_increaser("RfZ", charset, 2)) # outputs "Rgb"
This function might be used to get all permutations in some charsets.
So are you literally wanting to change the last two bits of the string to "FF"? If so, easy
string = "11223300"
modified_string = string[:-2] + "FF"
Edit from comments
hex_str = "0x11223300"
for i in range(256):
hex_int = int(hex_str, 16)
new_int = hex_int + 0x01
print(hex(hex_int))
hex_str = str(hex(new_int))
I'm trying to make an encryption function that encrypts plaintext messages but the problem is that if i input a key too large that goes past 'Z' then it goes onto greater unicode values.
My code:
def encrypt(var1,var2):
var3 = ""
for i in range(0, len(var1)):
if ord(var1[i])>64 and ord(var1[i])<90:
var3=var3+chr((ord(var1[i])+var2))
elif ord(var1[i])+var2>90:
???
else:
continue
return(var3)
How do I get it to loop 'Z' back to 'A'. I think I have to make an if statement like this but I'm not sure what to put into it.
elif ord(var1[i])+var2>90:
???
Here is my one! Im using the modulus operator to wrap around every 26 numbers (the number of letter between a-z). I also handle upper on lowercase separately.
def encrypt(data, shift):
result = ''
for c in data:
c_num = ord(c)
# is the letter lower case a - z?
if (c_num >= ord('a')) and (c_num <= ord('z')):
# get the letter number from 0 - 26
c_num = c_num - ord('a')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('a')
result += chr(c_num)
# is the letter upper case A - Z?
elif (c_num >= ord('A')) and (c_num <= ord('Z')):
# get the letter number from 0 - 26
c_num = c_num - ord('A')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('A')
result += chr(c_num)
return result
encrypt('aAbB', 2)
'cCdD'
encrypt('afZz', 2)
'chBb'
Here is the code golf version using list comprehension just for fun!
def encrypt(data, shift):
return ''.join([chr(((ord(c) - ord('a') + shift) % 26) + ord('a')) if ord(c) in range(ord('a'), ord('z')+1) else chr(((ord(c) - ord('A') + shift) % 26) + ord('A')) for c in data])
A straight-forward way would be to check if you have passed beyond Z, and modify the character in that case:
...
if var1[i] >= 'A' and var1[i] <= 'Z':
translated_char = chr(ord(var1[i])+var2)
if translated_char > 'Z':
# If the resulting character is beyond Z,
# we go 26 characters back
translated_char = chr(ord(translated_char)-26)
# Append the translated character to the output string
var3 += translated_char
...
You may want to consider more descriptive variable names -- you'll thank yourself if you revisit your code after two months :-)
I would recommend using the modulus operator to do what you are wanting. In python that is the % character. In modulus math. X % Y tells us what the remainder of X / Y is. For example. 27 % 26 is 1. Using this you can get your wrap around that you want. Here is a sample bit of code to encrypt a single character
def encrypt_character( valToEncrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToEncrypt) - ord('A')
# Perform the Encryption
retVal = ( x + keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
# end encrypt_character
Now if we feed the character "A" Into our encryption algorithm with a key of 13 we get "N" as shown:
>>> encrypt_character("A", 13)
'N'
The decrypt algorithm is very similar, except you do subtraction instead of addtion
def decrypt_character( valToDecrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToDecrypt) - ord('A')
retVal = ( x - keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
To encrypt a string you can use the following function:
from re import sub
def encrypt_message( message, key ):
# Convert the message text into a plain text with all spaces and
# punctuation removed.
plainText = sub(r'[^A-Z]', '', message.upper())
cipherText = ""
charIndex = 0
# Encrypt the message 1 character at a time
while charIndex < len(plainText):
cipherText += \
encrypt_character( plainText[charIndex], key)
charIndex += 1
return cipherText
This function can be called:
>>> encrypt_message("HELLO World!", key=23)
'EBIILTLOIA'
The decryption function is very similar to the encryption function, except it calls the decrypt utility instead of the encrypt utility.
I want to decrypt an encrypted file. I'm having trouble all the way at the bottom when converting it and comparing it to a dictionary (which is full of words). Can someone guide me in the right direction? I'm struggling comparing the two.
#this function takes a string and encrypts ONLY letters by k shifts
def CaeserCipher(string, k):
#setting up variables to move through
upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'*10000
lower = 'abcdefghijklmnopqrstuvwxyz'*10000
newCipher = ''
#looping each letter and moving it k times
for letter in string:
if letter in upper:
if upper.index(letter) + k > 25:
indexPosition = (upper.index(letter) + k)
newCipher = newCipher + upper[indexPosition]
else:
indexPosition = upper.index(letter) + k
newCipher = newCipher + upper[indexPosition]
elif letter in lower:
if lower.index(letter) + k > 25:
indexPosition = (lower.index(letter) + k)
newCipher = newCipher + lower[indexPosition]
else:
indexPosition = lower.index(letter) + k
newCipher = newCipher + lower[indexPosition]
else:
newCipher = newCipher + letter
return newCipher
f = open('dictionary.txt', "r")
dictionary = set()
for line in f:
word = line.strip()
dictionary.add(word)
print dictionary
#main file
#reading file and encrypting text
f = open('encryptMystery1.txt')
string = ''
out = open("plain1.txt", "w")
myList = []
for line in f:
myList.append(line)
for sentence in myList:
for k in range(26):
updatedSentence = CaeserCipher(sentence, k)
for word in updatedSentence.split():
if word in dictionary:
out.write(updatedSentence)
break
print myList
f.close()
out.close()
Let's tackle this in steps, and the first step is entitled
WHY DO YOU HAVE 260,000 CHARACTER LONG STRINGS IN A CAESAR CIPHER
Sorry, I don't mean to be overly dramatic, but you realize that's going to take up more space than, well, Space, don't you? And it's completely unnecessary. It's an ugly and slow hack to avoid understanding the % (modulo) operator. Don't do that.
Now, to the modulo:
Step two of course will have to be understanding the modulo. It's not actually hard, it's just like the remainder of a division problem. You remember when you were in school and just LEARNING division? 7/4 was 1r3 not 1.75, remember? Well Python has functions for all that. 7/4 == 1.75, 7//4 == 1 and 7 % 4 == 3. This is useful because it can serve to "wrap" a number around a fixed length.
Let's say for example you have some string with 26 indexes (like, I don't know, an alphabet?). You're trying to add some number to a starting index, then return the result but UGH YOU'RE ADDING 2 TO Y AND IT DOESN'T WORK! Well with modulo it can. Y is in index 24 (remember zero is its own index), and 24+2 is 26 and there IS no 26th index. However, if you know there's going to be only 26 elements in your string, we can take the modulo and use THAT instead.
By that logic, index + CONSTANT % len(alphabet) will ALWAYS return the right number using simple math and not sweet baby jesus the quarter million element long string you just butchered.
Ugh your mother would be ashamed.
Reversing a Caesar cipher
So you've got a good idea, going through each line in turn and applying every kind of cipher to it. If I were you I'd dump them all into separate files, or even into separate list elements. Remember though that if you're reversing the cipher, you need to use -k not k. It's probably a good idea to simply change your Caesar cipher to detect that though, since the modulo trick doesn't work in this case. Try something like:
def cipher(text, k):
cipherkey = "SOMESTRINGGOESHERE"
if k < 0:
k = len(cipherkey) + k
# len(cipherkey) - abs(k) would be more clear, but if it HAS to be
# a negative number to get in here, it seems silly to add the call
# to abs
Then you can do:
startingtext = "Encrypted_text_goes_here"
possibledecrypts = [cipher(startingtext, -i) for i in range(1,26)]
I have a file that has sequence on line 2 and variable called tokenizer, which give me an old position value. I am trying to find the new position.. For example tokenizer for this line give me position 12, which is E by counting letters only until 12. So i need to figure out the new position by counting dashes...
---------------LL---NE--HVKTHTEEK---PF-ICTVCR-KS----------
This is what i have so far it still doesn't work.
with open(filename) as f:
countletter = 0
countdash = 0
for line, line2 in itertools.izip_longest(f, f, fillvalue=''):
tokenizer=line.split()[4]
print tokenizer
for i,character in enumerate(line2):
for countletter <= tokenizer:
if character != '-':
countletter += 1
if character == '-':
countdash +=1
my new position should be 32 for this example
First answer, edited by Chad D to make it 1-indexed (but incorrect):
def get_new_index(string, char_index):
chars = 0
for i, char in enumerate(string):
if char != '-':
chars += 1
if char_index == chars:
return i+1
Rewritten version:
import re
def get(st, char_index):
chars = -1
for i, char in enumerate(st):
if char != '-':
chars += 1
if char_index == chars:
return i
def test():
st = '---------------LL---NE--HVKTHTEEK---PF-ICTVCR-KS----------'
initial = re.sub('-', '', st)
for i, char in enumerate(initial):
print i, char, st[get_1_indexed(st, i)]
def get_1_indexed(st, char_index):
return 1 + get(st, char_index - 1)
def test_1_indexed():
st = '---------------LL---NE--HVKTHTEEK---PF-ICTVCR-KS----------'
initial = re.sub('-', '', st)
for i, char in enumerate(initial):
print i+1, char, st[get_1_indexed(st, i + 1) - 1]
my original text looks like this and the position i was interested in was 12 which is 'E'
Actually, it's K, assuming you're using zero indexed strings. Python uses zero indexing so unless you're jumping through hoops to 1-index things (and you're not) it will give you K. If you were running into issues, try addressing this.
Here's some code for you that does what you need it to (albeit with 0-indexing, not 1-indexing). This can be found online here:
def get_new_index(oldindex, str):
newindex = 0
for c in str:
if c != '-':
if oldindex == 0:
return newindex
oldindex -= 1
newindex += 1
return 1 / 0 # throw a shitfit if we don't find the index
This is a silly way to get the second line, it would be clearer to use an islice, or next(f)
for line, line2 in itertools.izip_longest(f, f, fillvalue=''):
Here count_letter seems to be an int while tokenizer is a str. Probably not what you expect.
for countletter <= tokenizer:
It's also a syntax error, so I think this isn't the code you are running
Perhaps you should have
tokenizer = int(line.split()[4])
to make tokenizer into an int
print tokenizer can be misleading because int and str look identical, so you see what you expect to see. Try print repr(tokenizer) instead when you are debugging.
once you make sure tokenizer is an int, you can change this line
for i,character in enumerate(line2[:tokenizer]):