Caesar-Verschlüsselung

Code-Stücke können hier veröffentlicht werden.
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Hallo,

ich bin Python Anfänger hab zur Übung ein Caesar-Verschlüsselungsprogramm erstellt.
Wer nicht weiss was das ist http://de.wikipedia.org/wiki/Caesar-Ver ... %BCsselung.

Wollte nun fragen was ihr davon haltet? Was nicht gut daran ist, und was ich mir nicht bzw. was ich mir
aneignen sollte.

Code: Alles auswählen

class Cesar(object):
    def __init__(self):
        self.alphab = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
      

    def eingabe(self):
        self.text_eingabe = raw_input('Text eingeben (bitte keine Umlaute): ')
        self.schluessel = int(raw_input('Schluessel(zwischen 1 und 25) eingeben: '))
        self.auswahl = raw_input('Text verschluesseln oder entschluesseln? v/e: ')

        if self.auswahl == 'v':
            self.verschluesseln(self.schluessel)
        elif self.auswahl == 'e':
            self.entschluesseln(self.schluessel)

    def verschluesseln(self, schluessel):
        self.text_ausgabe = []
        self.schluessel = schluessel
        for i in self.text_eingabe.lower():
            if i == ' ':
                self.text_ausgabe.append(' ')
            else:
                self.pos = self.alphab.index(i)
                self.pos += self.schluessel
                if self.pos > 25:
                    self.pos = self.pos - 26
                    self.text_ausgabe.append(self.alphab[self.pos])
                else:
                    self.text_ausgabe.append(self.alphab[self.pos])
        self.ausgabe(self.text_ausgabe)

    def entschluesseln(self, schluessel):
        self.text_ausgabe = []
        self.schluessel = schluessel
        for i in self.text_eingabe.lower():
            if i == ' ':
                self.text_ausgabe.append(' ')
            else:
                self.pos = self.alphab.index(i)
                self.pos -= self.schluessel
                if self.pos > 25:
                    self.pos = self.pos - 26
                    self.text_ausgabe.append(self.alphab[self.pos])
                else:
                    self.text_ausgabe.append(self.alphab[self.pos])
        self.ausgabe(self.text_ausgabe)
        
    def ausgabe(self, text):
        self.text_ausgabe = text
        print ''.join(self.text_ausgabe)
        self.eingabe()

app = Cesar()
app.eingabe()
Merci für eure Antworten!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Zum Nachdenken:

Code: Alles auswählen

>>> import string
>>> string.lowercase
'abcdefghijklmnopqrstuvwxyz'

Code: Alles auswählen

>>> a = 40
>>> if a > 25: a = a - 26
... 
>>> a
14
>>> a = 40
>>> a = a % 26
>>> a
14
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Willkommen im Forum!

1. Schlimmer Fall von Klassenmissbrauch.
2. Warum ist die Ausgabe/Eingabe Teil des Ent-/Verschluesselns?
3. Schau mal hier fuer Ideen: http://www.python-forum.de/viewtopic.php?f=11&t=23686
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Wenn dir das Spaß gemacht hat, hab ich noch ne Zusatzaufgabe für dich: Entschlüsseln des Textes, ohne die "Verschiebezahl" (also 13 bei ROT13) zu kennen.

Link: http://de.wikipedia.org/wiki/H%C3%A4ufigkeitsanalyse


Edit: Typo
Zuletzt geändert von derdon am Montag 13. September 2010, 20:52, insgesamt 1-mal geändert.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

derdon hat geschrieben:Wenn dir das Spaß gemacht hat, hab ich noch ne Zusatzaufgabe für dich: Entschlüsseln des Textes, ohne die "Verschiebebzahl" (also 13 bei ROT13) zu kennen.

Link: http://de.wikipedia.org/wiki/H%C3%A4ufigkeitsanalyse
Falls dus nicht schaffst, ich hab hier im Forum schon ein Snippet zur Häufigkeitsanalyse gepostet
the more they change the more they stay the same
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

@numerix: Vorsicht, `string.lowercase` muss keinesfalls immer "abcdefghijklmnopqrstuvwxyz" sein, da es locale-abhängig ist. Man sollte da schon `string.ascii_lowercase` benutzen, wenn man "abcdefghijklmnopqrstuvwxyz" haben will.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

@Trundle: Ja, war mir bewusst - hab mich schon fast gewundert, warum es so lange gedauert hat, bis jemand drauf hinweist. Aber mal ehrlich: Bei einer Cäsar-Verschlüsselung für den Eigenbedarf ...

Wo wir schonmal dabei sind: Wieso liefert string.lowercase auf einem auf Deutsch eingestellten System keine Umlaute mit?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

@numerix: Wenn du das weißt, verstehe ich noch weniger, warum du es dann benutzt. Ich als Anfänger wäre jedenfalls verwirrt, wenn ich das in idle ausprobiere und etwas völlig anderes angezeigt wird.

Ob dort irgendwelche andere Zeichen angezeigt werden, liegt im wesentlichen an zwei Dingen. Zum einen, ob `locale.setlocale()` aufgerufen wird. Manche Umgebungen machen das (e.g. idle, bpython (noch)). Zum Anderen sieht der entsprechende Code, der dann `string.lowercase` und co neusetzt so aus:

Code: Alles auswählen

    /* create lowercase string */
    n = 0;
    for (c = 0; c < 256; c++) {
        if (islower(c))
            ul[n++] = c;
    }
    ulo = PyString_FromStringAndSize((const char *)ul, n);
Es werden also nur Werte von 0 bis 255 probiert, und da heutzutage eben in der Regel utf-8 benutzt wird, sind da die ganzen Umlaute und so nicht dabei. Alles in allem ist `string.lowercase` also völlig witzlos und wurde in Python 3 zu Recht entfernt.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Danke euch!

@numerix, werde deine Vorschläge(Verbesserungen) einbauen.

@cofi, zu 1. Meinst du damit das eine Klasse hier nicht gut ist weil es ohne auch geht und übersichtlicher ist?
2. Wie meinst du das?
3. Merci
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Die Klasse ist nicht gut, weil sie keinen Zweck erfuellt, ausser einen Namensraum zu bieten und das machen schon Module. Nein es ist sogar noch schlimmer, du benutzt Instanzvariablen fuer lokale. Ausserdem ist dein Ansatz reichlich beschraenkt, weil du nur Texte ent-/verschluesseln kannst die auch ueber die Klasse eingeben wurden.

Der Zweite Punkt schlaegt in diesselbe Kerbe: Alles ist zu sehr verknuepft und die Funktionen machen mehr als der Name es vermuten laesst.
Beispielsitzung:
Eingabe => Entschluesseln -> Ausgabe -> Eingabe

Dass auf das Entschluesseln eine Ausgabe folgt ist evtl noch verschmerzbar, aber warum veranlasst die Ausgabe eine erneute Eingabe?

Ja damit spart man sich ein echtes Menue, das in einer Endlosschleife laeuft, aber der Ansatz ist reichlich bruechig, weil Python keine beliebig tiefen Rekursionen zulaesst.
BlackJack

@marlene: Zu cofi's Punkten:

Ad 1) Das ist im Grunde keine richtige Klasse sondern nur Funktionen die dort zusammengefasst werden. Auch wenn die Werte über das Objekt "übergeben" ist das IMHO trotzdem keine ordentliche Klasse -- eher unsauberes kommunizieren über etwas `global`-Ähnliches. Ausserdem werden viele Werte unnötig an das Objekt gebunden die jeweils nur innerhalb einer Funktion verwendet werden. Besonders sinnfrei scheint mir `text_ausgabe` was an `ausgabe` als Argument übergeben wird und in der "Methode" an das Objekt gebunden obwohl genau das auch schon in den aufrufenden Methoden schon gemacht wurde.

Ad 2) Sowohl `verschluesseln()` als auch `entschluesseln()` rufen `ausgabe()` auf. So kann man die Funktionen nicht wirklich einfach wiederverwenden oder testen. Man sollte Ein- und Ausgabe nicht mit der Programmlogik vermischen.

Die Endlosrekursion durch den Aufruf von `eingabe()` am Ende von `ausgabe()` solltest Du auch sein lassen. Funktionsaufrufe sind keine Sprunganweisungen wie GOTO in BASIC. Bei Sprachen die keine effiziente Erkennung und Behandlung von Endrekursion garantieren, sollte man solche Aufrufe nicht machen. Das endet früher oder später in einem Laufzeitfehler weil der Aufrufstapel voll ist beziehungsweise das Rekursionslimit erreicht wurde.
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

So hab des jetzt noch mal gemacht.

Code: Alles auswählen

import string

def cesar(schluessel, text, option):
    text_codiert = ''
    for i in text:
        if i in string.ascii_letters:
            if option == 1:
                i = (string.ascii_letters.index(i) + schluessel) % len(string.ascii_letters)
                text_codiert += string.ascii_letters[i]
            elif option == 2:
                i = (string.ascii_letters.index(i) - schluessel) % len(string.ascii_letters)
                text_codiert += string.ascii_letters[i]
        else:
            text_codiert += i
    print text_codiert
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Das ist ja schon ein echter Fortschritt!
Nicht so günstig ist die Wahl von "i" als Bezeichner für die einzelnen Zeichen; damit assoziiert man meist eine natürliche Zahl. Besser wäre c (für character) oder z (für Zeichen) - je nachdem, ob du deutsche oder englische Bezeichner verwendest.

Nicht so schön ist der annähernd duplizierte Code für die beiden Optionen. Wenn du die Optionen wirklich so beibehalten willst (d.h. 1 und 2), dann könntest du es auch so machen:

Code: Alles auswählen

from string import ascii_letters as abc

def cesar(schluessel, text, option):
    return "".join((abc[(abc.index(c) - (2*option-3)*schluessel) % len(abc)] if c in abc else c) for c in text)

print cesar(5,"Hallo!",1)
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Gut ein Fortschirtt is ja schon mal was.

Wie wär es wenn ich zwei Funktionen daraus mache, eine verschluesseln und eine entschluesseln, wär aber vom
Code her auch ziemlich ähnlich?

Hätte noch ne ander Frage was nicht speziell den Code hier betrifft.

Wenn ich etwas programmieren will wie z.B. Cesar-Verschlüsselung. Weiss ich nicht wie ich anfangen soll, was alles zu beachten ist. Gibt es sowas wie einen Leitfaden nach dem man gehen kann? Was macht ihr wenn ihr ein
neues Programm/Project startet bevor ihr erst richtig anfängt?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

2 Funktionen sind besser, auch wenn sie aehnlich aussehen - aehnlichen Code kann man auslagern, da sie 2 verschiedene Dinge machen. Und auch im Sinne des Interfaces ist es besser 2 Funktionen zu haben als eine mit obskuren Opcodes zu fuettern.

Was meinst du mit Leitfaden? Was soll der abdecken? PEP 8 als Style Guide und Idiome und Anti-Idiome ist ein guter Anfang.

Bevor ich anfange lege ich ein Git-Repository an ... ich glaube aber nicht, dass du darauf raus willst ;) Also: Was willst du hoeren?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

cofi hat geschrieben:Also: Was willst du hoeren?
Ich denke mal, es geht um grundlegende Entscheidungen bereits bei ganz kleinen Programmen:
- Wie entscheide ich, was ich in eine Funktion hineinpacke?
- Bei objektorientierten Entwürfen: Welche Klassen baue ich etc.?

Meine Empfehlung wäre: Mach es so wie mit dem Cäsar-Snippet. Entwickle deinen Code so wie du ihn für gut hältst und lass dir von anderen, die schon mehr Erfahrung mit der Programmierung haben, dazu etwas sagen. Wenn man das dann nicht einfach unkritisch übernimmt ("Hauptsache es läuft"), sondern sich damit beschäftigt, lernt man dazu.
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Ich denke mal, es geht um grundlegende Entscheidungen bereits bei ganz kleinen Programmen:
- Wie entscheide ich, was ich in eine Funktion hineinpacke?
- Bei objektorientierten Entwürfen: Welche Klassen baue ich etc.?

Meine Empfehlung wäre: Mach es so wie mit dem Cäsar-Snippet. Entwickle deinen Code so wie du ihn für gut hältst und lass dir von anderen, die schon mehr Erfahrung mit der Programmierung haben, dazu etwas sagen. Wenn man das dann nicht einfach unkritisch übernimmt ("Hauptsache es läuft"), sondern sich damit beschäftigt, lernt man dazu.
Das hab ich damit gemeint, ob ich vorher schon festlegen sollte wie viele Funktionen, ob OOP etc. Sozusagen Vorbereitungen treffen bevor ich anfange was zu programmieren(auch bei so kleinen Sachen wie mit dem Cäsar-Snippet).
Aber auch Grundlegende Sachen wie z.B. soll ich den Code immer so klein halten wie möglich etc.

@numerix Ich werde mich an deine Empfehlung halten, und von anderen korrigieren lassen und hoffentlich dazu lernen.
BlackJack

@marlene: Wie viele Funktionen man schreiben will, kann man vorher ja gar nicht *genau* festlegen, weil es ja immer passieren kann, dass eine Funktion so lang wird, dass man sie besser aufteilt. Eine grobe Idee was man so braucht kann man sich vorher überlegen, bei Verschlüsselung zum Beispiel eine für die Ver- und eine für die Entschlüsslung. Aber wieviele Hilfsfunktionen man letztendlich schreibt, kann man auch während des Programmierens entscheiden. Wenn Funktionen zu lang werden, kann man sie aufteilen und wenn man irgendwo sich wiederholende Muster im Quelltext entdeckt, kann man die als Funktion herausziehen.

Bei so klein wie möglich ist die Frage was "klein" bedeutet. Ich würde sagen so einfach wie möglich ist ein gutes Ziel. Wobei das natürlich auch zu einem Teil subjektiv ist. Aber das "KISS"-Prinzip -- "Keep It Simple & Stupid" -- wird öfter empfohlen.

Dabei kann "test driven development" (TDD) helfen, bzw. wenn man das nicht konsequent durchhält, zumindest die Funktionen und Klassen so schreiben, dass man sie gut einzeln und isoliert auch automatisiert testen kann. Da würde dann zum Beispiel auch die Vermischung von Programmlogik und Ein-/Ausgabe oder die Endlosrekursion gar nicht erst passieren, denn das lässt sich ja überhaupt nicht gut testen.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

marlene hat geschrieben:Das hab ich damit gemeint, ob ich vorher schon festlegen sollte wie viele Funktionen, ob OOP etc. Sozusagen Vorbereitungen treffen bevor ich anfange was zu programmieren(auch bei so kleinen Sachen wie mit dem Cäsar-Snippet).
Aber auch Grundlegende Sachen wie z.B. soll ich den Code immer so klein halten wie möglich etc.
Wie soll dass den klappen? Ich denke nicht dass es überhaupt möglich ist bei einem nicht-trivialem Projekt soweit voraus zu planen, Software Design ist keine Architektur.

Das einzige was meiner Meinung nach Sinn macht ist dass grundlegende Design zu kennen, man sollte relativ unabhängig von der Sprache erklären können wie die Anwendung aufgebaut sein sollen sowie dessen Funktionsweise erklären können. Wenn man diese Fragen ohne Probleme und ohne groß nachzudenken beantworten kann sind alles andere Details.

Vorallem weil Ich mich auch durchaus oft dabei wieder finde mehrere Implementation eines bestimmten Designs auszuprobieren oder Teile des Designs während der Entwicklung zu ändern. Wenn man sich nicht die Flexibilität nimmt auf zukünftige Erfahrungen oder neues Wissen zu reagieren ist ein Projekt zum scheitern verurteilt, den am Ende weiß man es immer besser als vorher ;)
marlene
User
Beiträge: 26
Registriert: Montag 13. September 2010, 12:11

Zur Zusatzaufgabe:

Hab hier einen Code geschrieben , der Cesar Verschlüsselungen ohne die "Verschiebezahl" zu kennen entschlüsselt.

Code: Alles auswählen

import string

#Datei mit Codierten-Daten vorher erstellen(.txt), und als Parameter(Dateipfad) angeben.
#Das Zeichen, das am haufigsten vorkommt wird ausgegeben.
def einlesen(dateipfad):
    datei = open(dateipfad)
    text = datei.read()
    text.lower()
    dic = {}
    for z in text:
        i = text.count(z)
        dic[i] = z
    buchstabe_max = max(dic.keys())
    print dic[buchstabe_max]
    datei.close()

#Der Index(Buchstabe der am haufigsten vorkommt als Parameter angeben) zum verschieben zu 'e' wird ermittelt.
def index(buchstabe_max):
    buchstabe_max = buchstabe_max
    verschiebe_index = string.ascii_lowercase.index('e')-string.ascii_lowercase.index(buchstabe_max)
    print verschiebe_index

#Eingelesene Textdatei(Parameter) wird um den als Parameter angegebenen Wert verschoben und ausgegeben.    
def verschieben(verschiebe_index, dateipfad):
    datei = open(dateipfad)
    text = datei.read()
    text.lower()
    verschiebe_index = verschiebe_index
    text_ausgabe = []
    for z in text:
        if z not in string.ascii_lowercase:
            text_ausgabe.append(z)
        else:
            a = string.ascii_lowercase.index(z)
            b = a + verschiebe_index
            b = b % len(string.ascii_lowercase)
            text_ausgabe.append(string.ascii_lowercase[b])
    print ''.join(text_ausgabe)
    datei.close()
nja so toll is er wahrscheinlich nicht, über Kritik freu ich mich immer.
Antworten