2010-12-13 15 views
2

Ich habe mir ähnliche Themen angeschaut, aber keine Lösung, die ich finden kann, ist genau vergleichbar mit dem, was ich erreichen möchte.Chiffretext Letter Freq Substitution: Vergleich zweier Wörterbücher nach Wert und Änderung eines Textes

Ich habe einen verschlüsselten Text, der eine einfache Buchstabensubstitution basierend auf der Häufigkeit des Auftretens jedes Buchstabens im Text durchlaufen muss. Ich habe bereits eine Funktion, um den Text zu normalisieren (Kleinbuchstaben, keine Buchstabenbuchstaben, Nein, Zählbuchstabenvorkommen und dann die relative Häufigkeit jedes Buchstabens. Der Buchstabe ist der Schlüssel in einem Wörterbuch und die Häufigkeit ist der Wert.

ich habe die erwarteten Brief Frequenzen für AZ auch in einem separaten Wörterbuch (k = Buchstaben, v = Frequenz), aber ich bin ein wenig verwirrt durch das, was als nächstes zu tun.

Was ich denke, ich tun muss die normalisierte Chiffrat, das erwartete Brief freq dict [d1] und den Chiffre Buchstaben freq dict [d2] und iterieren, sie zu nehmen als (Teil psuedocode) folgt:

for word in text: 
    for item in word: 
     for k,v in d2.items(): 
      if d2[v] == d1[v]: 
       replace any instance of d2[k] with d1[k] in text 
    decoded_text=open('decoded_text.txt', 'w') 
    decoded_text.write(str('the decoded text') 

Hier möchte ich Text nehmen und sagen "Wenn der Wert in d2 mit einem Wert in d1 übereinstimmt, ersetze jede Instanz von d2 [k] durch d1 [k] im Text".

Mir ist klar, dass ich dort ein paar grundlegende Python-Logik-Fehler gemacht haben muss (ich bin relativ neu bei Python), aber bin ich auf dem richtigen Weg?

Vielen Dank im Voraus

Update:

Danke für alle Anregungen. Ich entschloss mich, die Methode von Karl Knechtel zu versuchen, mit einigen Änderungen, die in meinen Code passen. Allerdings habe ich immer noch Probleme (vollständig in meiner Implementierung)

Ich habe eine Dekodierungsfunktion gemacht, um die Chiffretext-Datei in Frage zu stellen. Dies ruft die zuvor ausgeführte Zählfunktion auf, die ein Wörterbuch (Buchstabe: Frequenz als Gleitkommazahl) zurückgibt. Dies bedeutete, dass der Code "make highcase version" nicht funktionieren würde, da k und v nicht floats waren und .upper nicht als Attribut annehmen konnten. Wenn Sie diese Dekodierfunktion aufrufen, erhalten Sie die Chiffretextzeichenfrequenzen und dann den Chiffriertext selbst, der noch kodiert ist.

def sorted_histogram(a_dict): 
    return [x[1] for x in sorted(a_dict.items(), key=itemgetter(1))] 

def decode(filename): 
    text=open(filename).read() 
    cipher=text.lower() 

    cipher_dict=count(filename) 

    english_histogram = sorted_histogram(english_dict) 
    cipher_histogram = sorted_histogram(cipher_dict) 

    mapping = dict(zip(english_histogram, cipher_histogram) 

    translated = ''.join(
    mapping.get(c, c) 
    for c in cipher 
    ) 
    return translated 

Antwort

0

Sie wollen nicht wirklich was zu tun ist Sie denken daran zu tun, weil die Frequenzen der Zeichen in der Probe im Allgemeinen nicht die genaue Häufigkeitsverteilung in den Referenzdaten übereinstimmen. Was Sie wirklich versuchen, ist das häufigste Zeichen zu finden und es durch "e" zu ersetzen, die nächsten und ersetzen Sie es durch "t" und so weiter.

Also, was wir tun werden, ist die folgende:

  1. (ich nehme an, Sie können bereits diesen Teil tun) Konstruieren Sie ein Wörterbuch der tatsächlichen Häufigkeit von Buchstaben im Geheimtext.

  2. Wir definieren eine Funktion, die ein {letter: frequency} Wörterbuch verwendet und eine Liste der Buchstaben in der Reihenfolge der Häufigkeit erstellt.

  3. Wir erhalten die Buchstaben in der Reihenfolge der Häufigkeit in unserer Referenz (d. H. Jetzt haben wir eine geordnete Liste der häufigsten Buchstaben in Englisch) und in der Probe (ähnlich).

  4. Unter der Annahme, dass der gebräuchlichste Buchstabe in der Stichprobe dem häufigsten englischen Buchstaben entspricht usw., erstellen wir ein neues Wörterbuch, das Buchstaben aus der ersten Liste in Buchstaben aus der zweiten Liste abbildet. (Wir könnten auch eine Übersetzungstabelle für die Verwendung mit str.translate erstellen.) Wir machen Groß- und Kleinbuchstaben des gleichen Wörterbuchs (ich gehe davon aus, dass Ihre ursprünglichen Wörterbücher nur Kleinbuchstaben haben) und führen sie zusammen.

  5. Wir verwenden diese Zuordnung, um den verschlüsselten Text zu übersetzen, wobei andere Zeichen (Leerzeichen, Interpunktion usw.) allein gelassen werden.

So:

# 2. 
import operator 
def sorted_histogram(a_dict): 
    return [ 
    x[1] # the value 
    for x in sorted(a_dict.items(), key=operator.itemgetter(1)) 
    # of each dict item, sorted by value (i.e. the [1] element of each item). 
    ] 

# 3. 
english_histogram = sorted_histogram(english_dict) 
cipher_histogram = sorted_histogram(cipher_dict) 

# 4. 
# Make the lowercase version 
mapping = dict(zip(english_histogram, cipher_histogram)) 
# Make the uppercase version, and merge it in at the same time. 
mapping.update(dict(
    (k.upper(), v.upper()) for (k, v) in zip(english_histogram, cipher_histogram) 
)) 

# 5. 
translated = ''.join(# make this list of characters, and string them together: 
    mapping.get(c, c) # the mapped result, if possible; otherwise the original 
    for c in cipher 
) 

# 6. Do whatever you want with 'translated' - write to file, etc. 
0

Zunächst einmal, es ist sehr unwahrscheinlich, dass die Frequenzen Ihnen eine genaue Übereinstimmung geben, es sei denn, Ihre Nachricht ist sehr lang. Daher müssen Sie möglicherweise einige manuelle Änderungen vornehmen, um die genaue Nachricht zu erhalten. Aber wenn die Frequenzen nahe genug ...

Sie könnten die Schlüssel der beiden Wörterbücher (Buchstaben) erhalten, durch ihre Werte (Frequenzen) sortiert:

letters_in_frequency_order = sorted(d1.keys(), key=lambda x: d1[x]) 

Dann biegen sie in Strings:

normal_alphabet = "".join(letters_in_frequency_order) 

verwenden sie dann die Zeichenfolge zu übersetzen:

import string 
transtable = string.maketrans(cypher_alphabet, normal_alphabet) 
cyphertext.translate(transtable) 
+0

Danke, gut getupft. Ich habe die Antwort aktualisiert, um stattdessen die Funktion sorted() zu verwenden. –

0
#!/usr/bin/env python 
from operator import itemgetter 
import string 

def frequency(text): 
    d = {} 
    for letter in text: 
     try: 
      d[letter] += 1 
     except: 
      d[letter] = 1 
    return d 

def alphabet(): 
    for alpha in string.letters: yield alpha 

def cipher(text): 
    expected = frequency(text) 
    flist = sorted(expected.iteritems(), key=itemgetter(1), reverse=True) 
    alphabet_generator = alphabet() 
    for char, freq in flist: 
     text = text.replace(char, alphabet_generator.next()) 
    return (text, expected) 

def decipher(text, expected): 
    nal = [ x[0] for x in sorted(expected.iteritems(), key=itemgetter(1), \ 
      reverse=True) ] 
    normal_alphabet = ''.join(nal) 
    transtable = string.maketrans(string.letters[:len(normal_alphabet)], \ 
            normal_alphabet) 
    return text.translate(transtable) 

Verbrauch:

if __name__ == '__main__': 
    s = "SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING" 
    ciphered, expected = cipher(s) 
    print s 
    print ciphered 
    print decipher(ciphered, expected) 

# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING 
# ciddbpjadbfekjhbnaqaegacbfcrlachbcmidoaeg 
# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING