I have to write a program that will decode a Ceasar cypher with any possible rotation length on a long string that will be imported into the program. I'm trying to figure out some pseudo coding on how I want to tackle this problem but there is one key thing that I cannot figure out.

I have no clue how to go about writing a function that will find the largest occurrence of a letter in a string, and use that percentage of occurrence to find the amount shifted from a standard percentage of letter usage in the English language.

Essentially what I want to do is find the most used letter in the string, then find the difference between the encoded string max used letter and a constant given, to find my rotation key. Then use that key to decode the string.

Any help with ideas of possible ways to create a function that will count the occurrence of letters in a string will be big step forward as I go on writing the rest of my program.

Dani AI

Generated

A practical, beginner-friendly route that avoids dictionaries: count letters with a 26-element list (one slot per a–z), find the index of the largest count, turn that index into the actual letter (so you can call ord() on it), then compute the Caesar key by comparing that letter to a chosen plaintext target (commonly 'e'). This ties ’s counting idea to ’s suggestion about using the difference in character codes, while keeping the implementation simple for .

def count_letters_simple(s):
    counts = [0] * 26
    for ch in s.lower():
        if 'a' <= ch <= 'z':
            counts[ord(ch) - ord('a')] += 1
    total = sum(counts)
    if total == 0:
        return None, 0, 0.0
    idx = max(range(26), key=lambda i: counts[i])
    most = chr(idx + ord('a'))
    return most, counts[idx], counts[idx] / total * 100.0

Once you have the most letter you can get a numeric key and decode. Example decode helper:

def caesar_decode(s, key):
    out = []
    for ch in s:
        if 'A' <= ch <= 'Z':
            base = ord('A')
            out.append(chr((ord(ch) - base - key) % 26 + base))
        elif 'a' <= ch <= 'z':
            base = ord('a')
            out.append(chr((ord(ch) - base - key) % 26 + base))
        else:
            out.append(ch)
    return ''.join(out)

# usage:
most, cnt, pct = count_letters_simple(ciphertext)
key = (ord(most) - ord('e')) % 26   # map observed-most -> 'e'
plaintext = caesar_decode(ciphertext, key)

Notes and troubleshooting: preserve case and non-letters as shown. For short or noisy ciphertext the top letter may not be e — try mapping to 't' or try every key and pick the result with the most English words (or use a chi-squared frequency score). If multiple letters tie, try each tied letter as a candidate. When you’re ready to learn dicts, collections.Counter will simplify counting, but the list approach above keeps concepts explicit while you get comfortable with ord() and modulo math.

Recommended Answers

All 6 Replies

Let me help you to find your first big step forward: type "python count letters in string" in google and click on the first link.

I have but most methods use a dictionary or complicated method which I haven't learned yet still being new to python. So I was hoping to talk about other methods to do it instead of having someone point me to something that I obviously would already have done. But thanks for the help anyway

This may give you some ideas:

>>> 'abcdefg'.count('a')
1
>>> import string
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> s = 'I have to write a program that will decode a Ceasar cypher with any possible rotation length'
>>> dd = dict(zip(string.ascii_lowercase, [s.count(c) for c in string.ascii_lowercase]))
>>> dd['e']
8
>>>

I can get a function to find the largest number of times any letter is used, but what I don't know is how to let python use the actual letter itself that is used the most. Such as if 'T' happens to be used the most then use the ascii value of ord(T) for the rest of my program instead of simply finding an int value telling me the most times anything is used.

I'm not sure i quite get what your trying to do?
Wouldn't "T" be the key to your dict, and the value is the total count as you say?

You just do undecoding with -most frequent code + code for most common letter to do opposite shift.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.