2

同様のトピックを見てきましたが、私が達成しようとしているものと正確に比較できる解決策はありません。

テキスト内の各文字の出現頻度に基づいて、単純な文字置換を行う必要がある暗号テキストがあります。私はすでにテキストを正規化する関数を持っています (小文字、文字以外の文字なし、 no 、文字の出現回数を数え、各文字の相対頻度を取得します。文字は辞書のキーであり、頻度は値です。

別の辞書に AZ の予想文字頻度 (k=文字、v=頻度) もありますが、次に何をすべきか少し混乱しています。

私がする必要があると思うのは、正規化された暗号テキスト、予想される文字 freq dict [d1]、および暗号文字 freq dict [d2] を取得し、次のように反復することです (一部の疑似コード)。

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')

ここでは、テキストを取得して、「d2 の値が d1 の値と一致する場合、d2[k] のインスタンスをテキスト内の d1[k] に置き換えます」と言いたいと思います。

私はそこにかなりの数の基本的なpythonロジックエラーを犯したに違いないことを認識しています(私はPythonで比較的新しいです)が、正しい方向に進んでいますか?

前もって感謝します

アップデート:

有益な提案をありがとうございました。私のコードに合うようにいくつかの変更を加えて、Karl Knechtel の方法を試すことにしました。しかし、私はまだ問題を抱えています (完全に私の実装で)

問題の暗号文ファイルを取得するデコード関数を作成しました。これは、以前に作成された count 関数を呼び出します。この関数は、辞書を返します (文字:浮動小数点としての頻度)。これは、k と v が浮動小数点数ではなく、属性として .upper を使用できないため、「大文字バージョンにする」コードが機能しないことを意味していました。したがって、このデコード関数を呼び出すと、暗号文の文字頻度が返され、暗号文自体がエンコードされたままになります。

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
4

3 に答える 3

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)

使用法:

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

# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING
# ciddbpjadbfekjhbnaqaegacbfcrlachbcmidoaeg
# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING
于 2010-12-13T01:59:37.447 に答える
0

まず、メッセージが非常に長い場合を除き、周波数が完全に一致する可能性はほとんどないことに注意してください。したがって、正確なメッセージを取得するには、手動で調整する必要がある場合があります。しかし、周波数が十分に近い場合...

両方の辞書 (文字) のキーを、値 (頻度) で並べ替えて取得できます。

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

次に、それらを文字列に変換します。

normal_alphabet = "".join(letters_in_frequency_order)

次に、それらを使用して文字列を翻訳します。

import string
transtable = string.maketrans(cypher_alphabet, normal_alphabet)
cyphertext.translate(transtable)
于 2010-12-13T01:40:57.187 に答える
0

一般に、サンプル内の文字の頻度は、参照データ内の正確な頻度分布と一致しないため、考えていることを実際には実行したくありません。あなたが実際にやろうとしているのは、最も一般的な文字を見つけて「e」に置き換え、次に多い文字を「t」に置き換える、ということです。

そこで、私たちがやろうとしていることは次のとおりです。

  1. (この部分は既に完了していると思います) 暗号文の実際の文字頻度の辞書を作成します。

  2. {文字: 頻度} 辞書を取り、頻度順に文字のリストを生成する関数を定義します。

  3. 文字を頻度順に、リファレンス (つまり、英語で最も一般的な文字の順序付きリストができました) とサンプル (同様に) に取得します。

  4. サンプルの最も一般的な文字が英語で最も一般的な文字に対応するという仮定に基づいて、最初のリストの文字を 2 番目のリストの文字にマッピングする新しい辞書を作成します。( で使用する変換テーブルを作成することもできますstr.translate。) 同じ辞書の大文字バージョンと小文字バージョンを作成し (元の辞書には小文字しかないと仮定します)、それらをマージします。

  5. このマッピングを使用して暗号文を翻訳し、他の文字 (スペース、句読点など) はそのままにします。

したがって:

# 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.
于 2010-12-13T01:41:42.990 に答える