Python 3 Vigenere-Chiffre
Ich bin noch ziemlich neu in Python und versuche herauszufinden, ob ich Module, Funktionen usw. effizient genutzt habe oder ob es einen anderen / einfacheren Weg gibt, etwas zu tun.
Diese Python 3 Vigenere-Verschlüsselung ist eine Neuerstellung einer JavaScript-basierten Verschlüsselung und basiert auf Windows. Es akzeptiert alle Buchstaben und verfügt über integrierte Demo-Optionen. Die Verschlüsselungsdemo verwendet Stufe 1 der CIA- Kryptos- Verschlüsselung.
#! python
import os
import re
## Initialize global variables
continue_cipher = ""
demo_alphabet = "KRYPTOSABCDEFGHIJLMNQUVWXZ"
demo_key = "PALIMPSEST"
demo_cipher_string = "EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJYQTQUXQBQVYUVLLTREVJYQTMKYRDMFD"
demo_cipher_decoded = "BETWEENSUBTLESHADINGANDTHEABSENCEOFLIGHTLIESTHENUANCEOFIQLUSION"
## Visuals
def display_header():
print("################################################")
print("# #")
print("# --- VIGENERE CIPHER --- #")
print("# #")
print("# A simple Vigenere cipher decoder/encoder #")
print("# #")
print("################################################", end="\n\n")
return
def display_results(mode, cipher_vars):
# Clear screen for final results
os.system('cls')
# Display header
display_header()
# Decompose cipher_vars
(alphabet, key, cipher_string, results) = cipher_vars
print("Mode:", "Decrypt" if mode == "D" else "Encrypt", end="\n\n")
print("Alphabet:", alphabet)
print("Key:", key)
print("Cipher String:", cipher_string, end="\n\n")
print("Decoded string:" if mode == "D" else "Encoded string:", results, end="\n\n")
return
## Validations
def string_is_alpha(input_string):
return True if re.match("^[a-zA-Z_]*$", input_string) else False
## Cipher variables
def get_alphabet():
global demo_alphabet
while True:
alphabet = input("Enter cipher alphabet: ").upper()
if alphabet == "":
alphabet = demo_alphabet
break
elif string_is_alpha(alphabet) is False:
print("The alphabet is not valid. Alphabet should not contain spaces, digits or special characters.")
else:
break
return alphabet
def get_key():
global demo_key
while True:
key = input("Enter cipher key: ").upper()
if key == "":
key = demo_key
break
elif string_is_alpha(key) is False:
print("The key is not valid. Key should not contain spaces, digits or special characters.")
else:
break
return key
def get_cipher_string(mode):
global demo_cipher_string
global demo_cipher_decoded
while True:
cipher_string = input("Enter cipher string: ").upper()
if cipher_string == "":
cipher_string = demo_cipher_string if mode == "D" else demo_cipher_decoded
break
elif string_is_alpha(cipher_string) is False:
print("The cipher string is not valid. Cipher strings should not contain spaces, digits or special characters.")
else:
break
return cipher_string
## Cipher actions
def get_cipher_alphabets(alphabet, key):
cipher_alphabets = []
for char in key:
char_index = alphabet.find(char)
cipher_alphabet = alphabet[char_index:] + alphabet[:char_index]
cipher_alphabets.append(cipher_alphabet)
return cipher_alphabets
def start_cipher(mode, alphabet, key, cipher_string):
mode_string = ""
cipher_alphabets = get_cipher_alphabets(alphabet, key)
cipher_alphabet_index = 0
for char in cipher_string:
# Reset cipher_alphabet_index to 0 when at end of cipher alphabets
if cipher_alphabet_index == len(cipher_alphabets):
cipher_alphabet_index = 0
# Use appropriate alphabet based on mode
# Syntax: base_alphabet[mode_alphabet.find(char)]
if mode == "D":
mode_string += alphabet[cipher_alphabets[cipher_alphabet_index].find(char)]
else:
mode_string += cipher_alphabets[cipher_alphabet_index][alphabet.find(char)]
cipher_alphabet_index += 1
return mode_string
## Cipher Mode
def get_cipher_mode():
while True:
cipher_mode = input("Choose cipher mode - [D]ecrypt or [E]ncrypt: ").upper()
if cipher_mode != "D" and cipher_mode != "E":
print("That is not a valid option. Please enter 'D' for decrypt and 'E' for encrypt.")
else:
break
print("")
return cipher_mode
def start_cipher_mode(mode):
print("Press 'enter' to use demo options")
alphabet = get_alphabet()
key = get_key()
cipher_string = get_cipher_string(mode)
mode_string = start_cipher(mode, alphabet, key, cipher_string)
return alphabet, key, cipher_string, mode_string
## Loop cipher
def get_continue_cipher():
while True:
continue_cipher = input("Do you want to decode/encode more? [Y/N]: ").upper()
if continue_cipher != "Y" and continue_cipher != "N":
print("That is not a valid option. Please enter 'Y' to continue and 'N' to quit.")
else:
break
return continue_cipher
## Start vigenere cipher program
while continue_cipher != "N":
# Clear the screen after each operation
os.system('cls')
# Display header
display_header()
# Determine cipher mode
cipher_mode = get_cipher_mode()
cipher_vars = start_cipher_mode(cipher_mode)
# Display results
display_results(cipher_mode, cipher_vars)
continue_cipher = get_continue_cipher()
Antworten
shebang
Der Shebang sollte generisch sein. Sie rufen gerade an python, was auf bestimmten Systemen möglicherweise auf Python 2 verweist.
Ein generischer, virtueller, umweltfreundlicher Python-Shebang ist:
#!/usr/bin/env python3
PEP-8
Einige Punkte aus dem PEP-8-Leitfaden :
- Umgeben Sie Funktions- und Klassendefinitionen der obersten Ebene mit zwei Leerzeilen.
- Verwenden Sie in Funktionen sparsam Leerzeilen, um logische Abschnitte anzuzeigen.
- Konstanten werden normalerweise auf Modulebene definiert und in Großbuchstaben mit Unterstrichen zwischen den Wörtern geschrieben.
PEP-484
Tippfunktionen erleichtern das Durchlaufen Ihrer Funktionen. Schauen Sie sich den PEP-484 an .
if __name__ Block
Fügen Sie die Ausführungslogik Ihres Skripts in den if __name__ == "__main__"Block ein. Eine aussagekräftigere Erklärung finden Sie unter Stapelüberlauf .
Redundante Logik
In Ihrem Code haben Sie 5 verschiedene Funktionen, nur um Benutzereingaben zu lesen. Alle haben die gleiche Aufgabe:
- Endlosschleife
- Fragen Sie nach Benutzereingaben
- in Großbuchstaben konvertieren
- Überprüfen Sie, ob die Eingabe leer ist (oder in einer Reihe gültiger Werte).
- Bei einem leeren Wert wird ein Standardwert zurückgegeben
- kehre mit dem Wert zurück
All dies könnte mit einer einzigen Funktion erledigt werden:
def ask_user_input(message: str, options: List[str] = None, default: str = None, check_alpha: bool = False) -> str:
if not any([options, default]):
raise ValueError("Either a set of `options` for validation or a fallback `default` needed.")
while True:
value = input(message).upper()
if options:
if value in options:
break
else:
print(f"Invalid value. Select one of {', '.join(options)}")
continue
if default is not None:
if not value:
value = default
break
elif not check_alpha:
break
elif not (value.isalpha() and value.isascii()):
print("The input text should only consist of ascii alphabets.")
continue
else:
break
return value
Regex / Validierung
Der reguläre Ausdruck für die Überprüfung der Eingabe ermöglicht _, während die Fehlermeldung ausdrücklich keine Sonderzeichen enthält. Die Überprüfung beim Umschreiben oben erfolgt mit (aktualisiert basierend auf dem Kommentar unten):
value.isalpha() and value.isascii()
Dies ist schneller als Regex (es sei denn, der Benutzer gibt weiterhin falsche Werte ein \$ 10^ n \$Zeiten, in denen das vorkompilierte Muster möglicherweise etwas besser abschneidet ).
Performance
Einige Dinge, die geändert werden können, um den Code leistungsfähiger zu machen:
Anstatt an eine Zeichenfolge zu verketten (anzuhängen)
mode_string, drücken Sie auf eine Liste und verwenden Sie am Ende"".join(). Weitere Details zum Stapelüberlauf .Sie können Ihr Programm auch Linux (* nix) -Systeme unterstützen lassen. Die einzige Abhängigkeit von Windows ist Ihr Systemaufruf an
cls. Vielleicht ( aus dem Stapelüberlauf ):def clear(): os.system("cls" if os.name == "nt" else "clear")Es gibt 2 Funktionen mit sehr ähnlichen Namen:
start_cipher(mode...)undstart_cipher_mode(mode). Dies macht es wirklich schwierig zu wissen, welcher die Chiffre wirklich startet . Vielleicht haben 2 separate Funktionenencryptunddecrypt?Mit der Modulo-Operation können Sie die folgenden Bedingungen entfernen:
if cipher_alphabet_index == len(cipher_alphabets): cipher_alphabet_index = 0und würde aussehen wie:
result.append(alphabet[cipher_alphabets[cipher_alphabet_index % alphabets_length].find(char)]Erstellen Sie
alphabetein Wörterbuch, da Sie die Zeichenfolge nur verwenden, um tatsächlich mit den Indexwerten der darin enthaltenen Zeichen zu arbeiten. Lookups im Wörterbuch ist \$ O(1) \$im Vergleich zu \$ O(n) \$für die.find(). Das wäre:from itertools import count alphabet_map = dict(zip(alphabet, count()))Aus den obigen 2 Punkten geht hervor, dass Sie nach der Benutzereingabe keine Zeichen / Alphabete mehr benötigen. Nur der Indexwert modulo ist von Bedeutung. Dies kann ohne ein beträchtliches mathematisches Verständnis schwer zu verstehen / zu implementieren sein, daher können Sie dies vorerst überspringen.
@hjpotter deckte die meisten meiner Kommentare ab.
Boolesche Werte
Python hat ein Konzept von wahrheitsgemäßen und falschen Werten, daher ist es vorzuziehen, Werte direkt als Boolesche Werte zu behandeln, anstatt sie mit Wahr oder Falsch zu vergleichen.
return True if re.match("^[a-zA-Z_]*$", input_string) else False
kann vereinfacht werden zu:
return re.match("^[a-zA-Z_]*$", input_string)
elif string_is_alpha(alphabet) is False:
Dies kann vereinfacht werden zu:
elif not string_is_alpha(alphabet):
Wenn allgemein, möchten Sie selten "is" zum Vergleich verwenden. (Die Hauptausnahme ist der Vergleich mit None.)
Reguläre Ausdrücke kompilieren
Dies ist mit ziemlicher Sicherheit eine unnötige Leistungsverbesserung, kann aber für später nützlich sein:
Der Aufruf von re.matchmuss den regulären Ausdruck bei jedem Aufruf kompilieren. Sie können den regulären Ausdruck einmal vorkompilieren und dann matchdas kompilierte Objekt aufrufen , um es zu beschleunigen.
Globals
Fast jedes Mal, wenn ich nach dem globalSchlüsselwort greife , stellt sich heraus, dass es ein Fehler ist.
Ich glaube nicht, dass Sie die Demo-IDs als global deklarieren müssen. Sie sollten bereits verfügbar sein (nur zum Lesen - wenn Sie versuchen, in sie zu schreiben, definieren Sie eine neue Variable im neuen Bereich, wobei die Originale ausgeblendet werden).