|
1 | 1 | """https://en.wikipedia.org/wiki/Atbash"""
|
2 | 2 |
|
3 | 3 | import string
|
| 4 | +from timeit import timeit # Moved to top-level as required |
4 | 5 |
|
5 | 6 |
|
6 | 7 | def atbash_slow(sequence: str) -> str:
|
7 | 8 | """
|
| 9 | + Atbash cipher implementation using ordinal values. |
| 10 | + Encodes/decodes by reversing the alphabet. |
| 11 | + |
8 | 12 | >>> atbash_slow("ABCDEFG")
|
9 | 13 | 'ZYXWVUT'
|
10 |
| -
|
| 14 | + |
11 | 15 | >>> atbash_slow("aW;;123BX")
|
12 | 16 | 'zD;;123YC'
|
13 | 17 | """
|
14 | 18 | output = ""
|
15 |
| - for i in sequence: |
16 |
| - extract = ord(i) |
17 |
| - if 65 <= extract <= 90: |
18 |
| - output += chr(155 - extract) |
19 |
| - elif 97 <= extract <= 122: |
20 |
| - output += chr(219 - extract) |
21 |
| - else: |
22 |
| - output += i |
| 19 | + for char in sequence: |
| 20 | + code = ord(char) |
| 21 | + if 65 <= code <= 90: # Uppercase A-Z |
| 22 | + output += chr(155 - code) |
| 23 | + elif 97 <= code <= 122: # Lowercase a-z |
| 24 | + output += chr(219 - code) |
| 25 | + else: # Non-alphabetic characters |
| 26 | + output += char |
23 | 27 | return output
|
24 | 28 |
|
25 | 29 |
|
26 | 30 | def atbash(sequence: str) -> str:
|
27 | 31 | """
|
| 32 | + Optimized Atbash cipher implementation using string translation. |
| 33 | + More efficient than ordinal-based approach. |
| 34 | + |
28 | 35 | >>> atbash("ABCDEFG")
|
29 | 36 | 'ZYXWVUT'
|
30 |
| -
|
| 37 | + |
31 | 38 | >>> atbash("aW;;123BX")
|
32 | 39 | 'zD;;123YC'
|
33 | 40 | """
|
| 41 | + # Create translation tables |
34 | 42 | letters = string.ascii_letters
|
35 |
| - letters_reversed = string.ascii_lowercase[::-1] + string.ascii_uppercase[::-1] |
36 |
| - return "".join( |
37 |
| - letters_reversed[letters.index(c)] if c in letters else c for c in sequence |
38 |
| - ) |
| 43 | + reversed_letters = string.ascii_lowercase[::-1] + string.ascii_uppercase[::-1] |
| 44 | + |
| 45 | + # Create translation mapping |
| 46 | + translation = str.maketrans(letters, reversed_letters) |
| 47 | + |
| 48 | + # Apply translation to each character |
| 49 | + return sequence.translate(translation) |
39 | 50 |
|
40 | 51 |
|
41 | 52 | def benchmark() -> None:
|
42 |
| - """Let's benchmark our functions side-by-side...""" |
43 |
| - from timeit import timeit |
44 |
| - |
| 53 | + """ |
| 54 | + Performance comparison of both Atbash implementations. |
| 55 | + Measures execution time using Python's timeit module. |
| 56 | + """ |
45 | 57 | print("Running performance benchmarks...")
|
46 |
| - setup = "from string import printable ; from __main__ import atbash, atbash_slow" |
47 |
| - print(f"> atbash_slow(): {timeit('atbash_slow(printable)', setup=setup)} seconds") |
48 |
| - print(f"> atbash(): {timeit('atbash(printable)', setup=setup)} seconds") |
| 58 | + setup = ( |
| 59 | + "from string import printable; " |
| 60 | + "from __main__ import atbash, atbash_slow" |
| 61 | + ) |
| 62 | + # Time the slow implementation |
| 63 | + slow_time = timeit("atbash_slow(printable)", setup=setup) |
| 64 | + print(f"> atbash_slow(): {slow_time:.6f} seconds") |
| 65 | + |
| 66 | + # Time the optimized implementation |
| 67 | + fast_time = timeit("atbash(printable)", setup=setup) |
| 68 | + print(f"> atbash(): {fast_time:.6f} seconds") |
49 | 69 |
|
50 | 70 |
|
51 | 71 | if __name__ == "__main__":
|
52 |
| - for example in ("ABCDEFGH", "123GGjj", "testStringtest", "with space"): |
| 72 | + # Test examples |
| 73 | + examples = ("ABCDEFGH", "123GGjj", "testStringtest", "with space") |
| 74 | + for example in examples: |
53 | 75 | print(f"{example} encrypted in atbash: {atbash(example)}")
|
| 76 | + |
| 77 | + # Run performance comparison |
54 | 78 | benchmark()
|
0 commit comments