Verschlüsselung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Brevista
User
Beiträge: 32
Registriert: Sonntag 2. Juli 2017, 00:48

ich habe gerade versucht ein Verschlüsselungsprogramm zu schreiben zuerst sah es so aus:

Code: Alles auswählen

def verschlüsselung(satz,key):
    re = ""
    for buchstabe in satz:
        re = re + chr(ord(buchstabe) + ord(key))
    return re
dann hatte ich eine Fehler und habe festgestellt das man nur einen key mit länge von einem string verwenden kann.

Code: Alles auswählen

def verschlüsselung(satz,key):
    re = ""
    for buchstabe in satz :
        re = re + chr(ord(buchstabe) + ord(key[buchstabe%len(key)]))
    return re
ich habe mich informiert und festgestellt das der code so lauten muss

Code: Alles auswählen

def verschlüsselung(satz,key):
    re = ""
    for buchstabe in range(len(satz)):
        re = re + chr(ord(satz[buchstabe]) + ord(key[buchstabe%len(key)]))
    return re
wieso muss man hier diese range(len(satz)) einbauen? und kann das nicht einfach nur so mit buchstabe in satz machen?



ganzer code am ende

Code: Alles auswählen

eingabe_satz = input("Satz: ")

eingabe_key = input("Key: ")

def verschlüsselung(satz,key):
    re = ""
    for buchstabe in range(len(satz)):
        re = re + chr(ord(satz[buchstabe]) + ord(key[buchstabe%len(key)]))
    return re

def entschlüsselung(satz,key):
    re = ""
    try:
        for buchstabe in range(len(satz)):
            re = re + chr(ord(satz[buchstabe]) - ord(key[buchstabe%len(key)]))
        return re
    except:
        re = re + "ERROR"
        return re

satz = eingabe_satz
key = eingabe_key

print(verschlüsselung(satz,key))
print(entschlüsselung(satz,key))
Zuletzt geändert von Anonymous am Mittwoch 12. Juli 2017, 12:16, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Brevista: for-Schleifen machen etwas mit jedem Element der Sequenz. buchstabe erhält also alle Buchstaben von satz, aber das ist kein Index.
Braucht man zusätzlich einen Index, würde man das mit enumerate machen:

Code: Alles auswählen

for index, buchstabe in enumerate(satz):
    re = re + chr(ord(buchstabe) + ord(key[index%len(key)]))
Hier willst Du aber über zwei Sequenzen gleichzeitig laufen, wobei die eine davon wiederholt werden soll. Das macht man dann mit zip und repeat

Code: Alles auswählen

from itertools import repeat
for buchstabe, key_buchstabe in zip(satz, repeat(key)):
    re = re + chr(ord(buchstabe) + ord(key_buchstabe))
oder kurz:

Code: Alles auswählen

def verschlüsselung(satz, key):
    return ''.join(chr(ord(buchstabe) + ord(key_buchstabe))
        for buchstabe, key_buchstabe in zip(satz, repeat(key))]
Ein nacktes except ist böse, weil dadurch eine Fehlersuche unmöglich gemacht wird. Überleg Dir mal, welche konkrete Exception in Deinem try-Block auftreten könnte.
BlackJack

@Brevista: Warum das mit ``buchstabe in satz`` nicht geht, wird Dir die Fehlermeldung ja verraten haben.

Und bei der ``range(len(satz)):``-Lösung ist der Name `buchstabe` falsch, denn die Schleifenvariable wird in dem Fall ja gar nicht an Buchstaben gebunden sondern an Zahlen die als Indexwerte verwendet werden.

Warum heisst das eigentlich `verschlüsselung()`, und `satz`, dann aber `key` und nicht `schlüssel`?

`re` ist kein guter Name für das Ergebnis, denn das ist eine Abkürzung. Zudem noch eine die üblicherweise für „regular expression“ steht, wie beim `re`-Modul in der Standardbibliothek.

Wiederholtes zusammensetzen von Zeichenketten mit ``+`` in einer Schleife ist nicht gut, da potentiell sehr ineffizient, da Zeichenketten nicht veränderbar sind und man deshalb damit rechnen muss das für jede neue Teilzeichenkette das bisherige und das neue in eine neu erstellte Zeichenkette kopiert werden müssen und die beiden Teile wieder freigegeben werden. Darum sammelt man die Teile besser in einer Liste und setzt die am Ende mit `join()` zusammen:

Code: Alles auswählen

def verschlüsselung(satz, schlüssel):
    ergebnis = list()
    for i in range(len(satz)):
        ergebnis.append(chr(ord(satz[i]) + ord(schlüssel[i % len(schlüssel)])))
    return ''.join(ergebnis)
Den Index braucht man ja eigentlich nur für den Schlüssel, deshalb kann man auch über die Buchstaben des Satzes *und* den Index iterieren (und die Umwandlung von Zahlen in Zeichen habe ich in die letzte Zeile verschoben):

Code: Alles auswählen

def verschlüsselung(satz, schlüssel):
    ergebnis = list()
    for i, buchstabe in enumerate(satz):
        ergebnis.append(ord(buchstabe) + ord(schlüssel[i % len(schlüssel)]))
    return ''.join(map(chr, ergebnis))
In Python gibt es oft einen Weg ohne Indexvariablen. Hier Beispielsweise über `itertools.cycle()` und `zip()` (+ Umwandlung der Zeichen von Satz und Schlüssel aus der Schleife heraus gezogen):

Code: Alles auswählen

def verschlüsselung(satz, schlüssel):
    ergebnis = list()
    for wert, schlüssel_wert in zip(map(ord, satz), cycle(map(ord, schlüssel))):
        ergebnis.append(wert + schlüssel_wert)
    return ''.join(map(chr, ergebnis))
Hier bräuchte man die Ergebnisliste nicht mehr sondern käme auch mit einem Generatorausdruck hin:

Code: Alles auswählen

def verschlüsselung(satz, schlüssel):
    ergebnis = (
        wert + schlüssel_wert
        for wert, schlüssel_wert
        in zip(map(ord, satz), cycle(map(ord, schlüssel)))
    )
    return ''.join(map(chr, ergebnis))
Wenn das ``wert + schlüssel_wert`` nicht etwas zu kurz gedacht wäre, dann könnte man auch `operator.add()` und `itertools.starmap()` verwenden:

Code: Alles auswählen

def verschlüsselung(satz, schlüssel):
    ergebnis = starmap(add, zip(map(ord, satz), cycle(map(ord, schlüssel))))
    return ''.join(map(chr, ergebnis))
Man könnte `add()` dann durch eine eigene `wert_verschlüsseln()`-Funktion ersetzen die das Problem vom einfachen Addieren/Subtrahieren nicht mehr hat. Ich würde so eine Ver-/Entschlüsselung auch auf Bytes definieren und nicht auf Zeichen. Dann kann man *alles* ver-und entschlüsseln, weil sich alles als Bytes ausdrücken lässt.

Ein nacktes ``except:`` ohne konkrete Ausnahme(n) anzugeben ist fast nie eine sinnvolle Fehlerbehandlung. Damit erschwert man sich die Fehlersuche, denn das behandelt *alle* Ausnahmen. Auch solche mit denen man gar nicht rechnet.

Hier ”verschluckst” Du die Fehlerursache auch noch, das heisst man bekommt nicht heraus *was* der Fehler war. Und der Aufrufer kann einen Fehler noch nicht einmal erkennen und darauf reagieren. Wenn beim Aufruf von `entschlüsselung()` der Wert 'ERROR' zurückgegeben wird, hat dann jemand das Wort 'ERROR' verschlüsselt, oder ist beim entschlüsseln ein Fehler aufgetreten?

Ansonsten Unterscheiden sich die beiden Funktionen nur durch einen einzigen Operator. Das würde man dann besser in eine Funktion herausziehen die diesen Operator als Argument bekommt, und von den anderen Beiden Funktionen aufgerufen wird. Die Operatoren gibt es im `operator`-Modul alle auch als Funktionen.

Die Zeilen 21 und 22 machen keinen Sinn.

Das das Hauptprogramm auf Modulebene steht und auch noch von Funktionsdefinitionen unterbrochen wird, ist unübersichtlich. Üblicherweise steht das Hauptprogramm in einer Funktion die `main()` heisst.
Antworten