How would you code a program ( preferably in Java or Python ) to break a random ciphertext where key can't be determined by shifts i.e the key substitution is random.
This website (https://www.guballa.de/substitution-solver) has done it.
I have to do it by frequency analysis (https://en.wikipedia.org/wiki/Frequency_analysis)
The main problem I am facing is to check that if the words are looking like English words or not when I substitute.
Please guide me on how to approach this problem
Thanks
hakid
This is maybe a late answer but this code can used as a start for you.
from operator import itemgetter
letterFrequency = [
[12.00, 'E'], [9.10, 'T'],
[8.12, 'A'], [7.68, 'O'],
[7.31, 'I'], [6.95, 'N'],
[6.28, 'S'], [6.02, 'R'],
[5.92, 'H'], [4.32, 'D'],
[3.98, 'L'], [2.88, 'U'],
[2.71, 'C'], [2.61, 'M'],
[2.30, 'F'], [2.11, 'Y'],
[2.09, 'W'], [2.03, 'G'],
[1.82, 'P'], [1.49, 'B'],
[1.11, 'V'], [0.69, 'K'],
[0.17, 'X'], [0.11, 'Q'],
[0.10, 'J'], [0.07, 'Z']]
plain_to_cipher = {
"a": "l", "b": "f",
"c": "w", "d": "o",
"e": "a", "f": "y",
"g": "u", "h": "i",
"i": "s", "j": "v",
"k": "z", "l": "m",
"m": "n", "n": "x",
"o": "p", "p": "b",
"q": "d", "r": "c",
"s": "r", "t": "j",
"u": "t", "v": "q",
"w": "e", "x": "g",
"y": "h", "z": "k",
}
cipher_to_plain = {v: k for k, v in plain_to_cipher.items()}
alphabet = "qwertyuioplkjhgfdsazxcvbnm"
message = input("Enter message to encrypt: ")
message = message.lower()
ciphertext = ""
for c in message:
if c not in alphabet:
ciphertext += c
else:
ciphertext += plain_to_cipher[c]
print("\nRandom substitution Encryption is: \n\t{}".format(ciphertext))
# .......................................................................
# calculate letter frequency of ciphertext
letter_list = []
cipher_len = 0
for c in ciphertext:
if c in alphabet:
cipher_len += 1
if c not in letter_list:
letter_list.append(c)
letter_freq = []
for c in letter_list:
letter_freq.append([round(ciphertext.count(c) / cipher_len * 100, 2), c])
# ....................................................................................
# Now sort list and decrypt each instance of ciphertext according to letter frequency
letter_freq = sorted(letter_freq, key=itemgetter(0), reverse=True)
decrypted_plaintext = ciphertext
index = 0
for f, c in letter_freq:
print("Replacing {} of freq {} with {}.".format(c, f, letterFrequency[index][1]))
decrypted_plaintext = decrypted_plaintext.replace(c, letterFrequency[index][1])
index += 1
print("\nThe Plaintext after decryption using frequency analysis: \n\t{}".format(decrypted_plaintext))
SIDE NOTES: this program can most of the time successfully decrypt most used letters like e, t, a, o but would fail to successfully map less used letters(since frequency differences start to decrease making results less predictable). This problem can be overcomed a little bit by also analyzing English most used bigrams(like th) and using the results to make more accurate predictions. Another note you can take advantage of is that the letter a is easy to break making breaking the letter i less painfull since any sentence having one ciphertext character in between is likely to correspond to a(ex: a book) or i(ex: i went)(and we already deduced a so any other single ciphertext character is likely to be i)
Related
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 10 months ago.
I am trying to get my code to go through each element in a list and decipher if it's the letter C. If it's a C remove it and print out the edited list.
Below is my code and it keeps looping.
letters = ["A", "B", "C", "D", "E", "C", "G"]
counter = 0
for letter in letters:
while letter != "":
if letter in letters == "C":
letters.remove("C")
counter += 1
print(letters)
You can do something like this:
With the pop argument
letters = ["A", "B", "C", "D", "E", "C", "G"]
counter = 0
i=0
while i < len(letters):
if i<len(letters) and letters[i] == "C":
letters.pop(i)
counter += 1
else:
i+= 1
print(letters) #['A', 'B', 'D', 'E', 'G']
You can remove the counter and obtain the number of "C" in the list by doing:
letters.count("C") at the begging
And you can use that to do:
With remove
letters = ["A", "B", "C", "D", "E", "C", "G"]
for _ in range(letters.count('C')):
letters.remove('C')
print(letters) #['A', 'B', 'D', 'E', 'G']
You can also use a list comprehension like that:
With list comprehension
letters = ["A", "B", "C", "D", "E", "C", "G"]
letters = [l for l in letters if l != 'C']
print(letters) #['A', 'B', 'D', 'E', 'G']
Or, you could also use filter with a lambda function:
With filter
letters = ["A", "B", "C", "D", "E", "C", "G"]
letters = [*filter(lambda l: l!='C', letters)]
print(letters) #['A', 'B', 'D', 'E', 'G']
i want to put the new keys that i found and printing a new string that create a logical sentence:
words = {'h': 'e', 'k': 't', 'm': 'o', 'u': 'r', 'e': 'h', 't': 'k', 'o': 'm', 'r': 'u'}
def text(str):
print('the original text', str)
original_text = 'puackich, hvhnkrally oaths phufhck. all ymr nhhd is pykemn. j.u.u.u kmltin.mmps iks nmk eio; ---> hkmu'
print(original_text)
if x == original_text:
print(True)
else:
what should i do?
If you want to decode the string according the dictionary words, you can use next example str.join + dict.get. For example:
words = {
"h": "e",
"k": "t",
"m": "o",
"u": "r",
"e": "h",
"t": "k",
"o": "m",
"r": "u",
}
def text(s):
print("the original text", s)
print("".join(words.get(ch, ch) for ch in s))
original_text = "puackich, hvhnkrally oaths phufhck. all ymr nhhd is pykemn. j.u.u.u kmltin.mmps iks nmk eio; ---> hkmu"
text(original_text)
Prints:
the original text puackich, hvhnkrally oaths phufhck. all ymr nhhd is pykemn. j.u.u.u kmltin.mmps iks nmk eio; ---> hkmu
practice, eventually makes perfect. all you need is python. j.r.r.r tolkin.oops its not him; ---> etor
Problem is i have list of dictionaries for example:
lst = [{"a": "AA", "b": "BB"},
{"a": "ok", "b": "ok"},
{"a": "AA", "b": "BB", "c": "CC"}]
Those two records are duplicates (key "a" have same value):
[{"a": "AA", "b": "BB"},
{"a": "AA", "b": "BB", "c": "CC"}]
I tried
duplicated = set()
records_output =\
[x for x in lst if [(x["a"]) not in duplicated, duplicated.add((x["a"]))][0]]
It removes one with most keys, but i want to remove one with lesser keys so i get
[{"a": "ok", "b": "ok"},
{"a": "AA", "b": "BB", "c": "CC"}]
My solution for this problem.
records are input
# all str/int values found by key
values = [r[key_name] for r in records]
# duplicated values
duplicates = [val for val, count in Counter(values).items() if count > 1]
# iterate over each value
for val in duplicates:
duplicated_temp = []
# finding all records with provided key/value
for r in records:
if(r[key_name] == val):
duplicated_temp.append(r)
# finding record with most key
record_to_preserve = duplicated_temp[0]
for dup in duplicated_temp:
if(len(dup.keys()) > len(record_to_preserve.keys())):
record_to_preserve = dup
# iterate over duplicated
# remove all from records except one with most keys
for r in duplicated_temp:
if(r != record_to_preserve):
records.remove(r)
return records
I am new to python. I'd like to ask for your assistance regarding operations with dictionaries. I guess, the question is a bit basic. But, I'm kinda stuck.
I need to get the total of values in dict2 corresponding the "JJ" values in dict1. Since "JJ" in dict1 is associated with keys "A" and "B", the corresponding values in dict2 are 30 and 100, which sums to 130
Thank you!
Rn
My code (I'm getting the sum of all values in dict2=145 after step 2 instead of just A+B=130)
dict1 = {"A":"JJ", "B":"JJ", "C":"X"}
dict2 = {"A":30, "B":100, "C":15}
dict3=dict()
for (kk, vv) in dict1.items():
ref_val="JJ"
if vv == ref_val:
dict3[kk] = vv
print(dict3)
total_points=0
for (kk, vv) in dict2.items():
for (kk, vv) in dict3.items():
total_points = sum(vv for vv in dict2.values())
print(total_points)
I hope I understood the question correctly.
I so, this should work:
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
keys = set(k for k, v in dict1.items() if v == "JJ")
total_points = sum(dict2.get(k, 0) for k in keys)
print(total_points)
keys: using list comprehension the keys having value equal to JJ are selected
total_points: the values corresponding to those keys are fetch from dict2 and summed on the fly. If a key from keys is not present in dict2 (which is not the case, btw) 0 (zero) is fetched instead (so it won't affect the sum)
I like the other answer but I would probably solve this problem a little more generically:
from collections import defaultdict
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = defaultdict(list)
for key, val in dict1.items():
val_to_keys[val].append(dict2.get(key, 0))
# Note that now val_to_keys contains:
# {'JJ': [30, 100], 'X': [15]}
if 'JJ' in val_to_keys:
print(sum(val_to_keys['JJ'])) # 130
# or you can one line the print
print(sum(val_to_keys.get('JJ', []))) # 130
This way you can only need to iterate over the dict1 once and you can pull out any value you want.
Note that if all you care about is the sums then it can be even more efficient by calculating the sum during the initial iteration. (I use a normal dict instead of a defaultdict here just to show how you can do it both with regular dictionaries and defaultdicts).
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = {}
for key, val in dict1.items():
val_to_keys[val] = val_to_keys.get(val, 0) + dict2.get(key, 0)
# Note that now val_to_keys contains:
# {'JJ': 130, 'X': 15}
if 'JJ' in val_to_keys:
print(val_to_keys['JJ']) # 130
I will get a dictionary which contains sub dictionaries and key : val pairs.
for Example :
dict = {"1" : "one", "2" : "two", "3" : {"one" : "1", "two" : "2"}}
this dictionary is not fixed i will get it randomly and it is contains multiple key : val pairs and some sub dicts.
My requirement is to loop through all keys, values and delete the key, val pair if i found a string in it in that particular sub dict.
def delete_key(dict_obj):
for key, val in dict_obj.items():
if type(val) == 'dict':
delete_key(val)
if type(val) == 'str':
print(key + ' - > ' + val)
# Below line will delete you key
del dict_obj[val]
# DO YOUR VERIFICATION LOGIC HERE
# AND DELETE KEY
Use above method to remove key. Fine tune this method as per your requirement.
a = {"1": {"a": "a"}, "2": "a", "3": {"p": "pi", "t": "ti"}}
print(a)
for el in a:
if type(a[el]) is dict:
for inner_el in a[el]:
print(a[el])
if a[el][inner_el] == "ti":
del(a[el][inner_el])
break
print(a)
output
{'1': {'a': 'a'}, '2': 'a', '3': {'p': 'pi', 't': 'ti'}}
{'a': 'a'}
{'p': 'pi', 't': 'ti'}
{'p': 'pi', 't': 'ti'}
{'1': {'a': 'a'}, '2': 'a', '3': {'p': 'pi'}}
this works only if there is one key to delete