Shiyan12

Задача 2

Dec 27th, 2019
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.35 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3.  
  4. import re
  5.  
  6. def find_all(s1, s2):
  7.     res = []
  8.     st = 0
  9.     st = s2.find(s1, st)
  10.     while st != -1:
  11.         res.append(st)
  12.         st += len(s1)
  13.         st = s2.find(s1, st)
  14.     return res
  15.  
  16. # делители числа n
  17. def get_factors(n):
  18.     res = []
  19.     for i in range(1, n + 1):
  20.         if n % i == 0:
  21.             res.append(i)
  22.     return res
  23.  
  24. def decrypt(c, k):
  25.     n = 26
  26.     t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  27.     k *= len(c) // len(k) + 1
  28.     m = ''
  29.     for i in range(len(c)):
  30.         cj = t.find(c[i])
  31.         kj = t.find(k[i])
  32.         mj = (cj + n - kj) % n
  33.         m += t[mj]
  34.     return m
  35.  
  36. s1 = input()
  37.  
  38. # избавляемся от всех лишних символов в строке
  39. s2 = ''
  40. for c1 in s1:
  41.     if c1.isalpha():
  42.         s2 += c1
  43.        
  44. # приводим всю строку к одному регистру
  45. s2 = s2.upper()
  46.  
  47. # рассматриваем 3-граммы, 4-граммы и 5-граммы
  48. grs = set()
  49. for n in [3, 4, 5]:
  50.     for i in range(len(s2) - n + 1):
  51.         gr = s2[i:i + n]
  52.         if s2.count(gr) > 1:
  53.             grs.add(gr)
  54. grs = list(grs)
  55.  
  56. # определяем расстояния между n-граммами
  57. ds = set()
  58. for gr in grs:
  59.     d = find_all(gr, s2)
  60.     for i in range(1, len(d)):
  61.         for j in range(i):
  62.             ds.add(d[i] - d[j])
  63.  
  64. # находим делители этих чисел
  65. c = {}
  66. for d in ds:
  67.     fs = get_factors(d)
  68.     fs.remove(1)
  69.     for f in fs:
  70.         c[f] = c.get(f, 0) + 1
  71. list_c = list(c.items())
  72. list_c.sort(key=lambda c: -c[1])
  73. c = dict(list_c)
  74.  
  75. # буквы по убыванию частоты встречаемости в английском языке
  76. en = 'ETAOINSHRDLCUMWFGYPBVKJXQZ'
  77.  
  78. lens = set()
  79.  
  80. f = open('dictionary.txt', 'r')
  81. lines = []
  82. for line in f:
  83.     lens.add(len(line.strip()))
  84.     lines.append(line.strip())
  85.        
  86. p = re.compile(r"[A-Za-z]+")
  87. w1 = p.search(s1).group(0)
  88.  
  89. # выделение символов
  90. for k in c.keys():
  91.     cs = []
  92.     for i in range(k):
  93.         s3 = s2[i::k]
  94.         mx_o = -1
  95.         cs.append([])
  96.         for j in range(ord('A'), ord('Z') + 1):
  97.             s4 = decrypt(s3, chr(j))
  98.             nu = list(en)
  99.             nu.sort(key=lambda elem: (-s4.count(elem), -en.find(elem)))
  100.             nu = ''.join(nu)
  101.             o = len(set(en[:6]) & set(nu[:6]))
  102.             o += len(set(en[-6:]) & set(nu[-6:]))
  103.             if o == mx_o:
  104.                 cs[-1].append(chr(j))            
  105.             if o > mx_o:
  106.                 mx_o = o
  107.                 cs[-1] = [chr(j)]
  108.     ks = []
  109.     queue = ['']
  110.     while queue:
  111.         v = queue.pop(0)
  112.         if len(v) < len(cs):
  113.             for w in cs[len(v)]:
  114.                 queue.append(v + w)
  115.         else:
  116.             m = decrypt(s2, v)
  117.             w2 = m[:len(w1)]
  118.             if w2 in lines:
  119.                 print(v.lower())
  120.                 i = 0
  121.                 res = ''
  122.                 for c2 in s1:
  123.                     if c2.isalpha():
  124.                         if c2.islower():
  125.                             res += m[i].lower()
  126.                         else:
  127.                             res += m[i]
  128.                         i += 1
  129.                     else:
  130.                         res += c2
  131.                 print(res)
  132.                 quit()
Add Comment
Please, Sign In to add comment