morsecode translator

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Pad385
User
Beiträge: 39
Registriert: Dienstag 12. März 2019, 18:33

haben wahrscheinlich viele von euch schonmal geschrieben hier ist meine Version davon
Wünsche, Kritik und Lob sind erwünscht!
und falls Sirius hier drüber schaut auch hier hatte ich die variable text_in zuvor morse_in_text und text_in_morse benannt was ja wieder unnötig war^^

Code: Alles auswählen

from time import sleep
from re import match
morsecode = {
    "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" : "--..", 
    "0" : "-----", 
    "1" : ".----", 
    "2" : "..---", 
    "3" : "...--", 
    "4" : "....-", 
    "5" : ".....", 
    "6" : "-....", 
    "7" : "--...", 
    "8" : "---..", 
    "9" : "----.", 
    "." : ".-.-.-", 
    "," : "--..--"
}
morsecode_reversed = {
    value:key for key,value in morsecode.items()
}
lst = (
    'm2t', 't2m'
)
print(
    '\tHerzlich Willkommen!\n\tMorsecode Translator v2.0\tAutor: Pad'
)
text_in = ''
while text_in.lower() != 'exit':
    question = input(
        '\tVon Morsecode zu Text oder von Text zu Morsecode? (m2t/t2m) : '
    )
    if question not in lst:
        print(
            '\tvalue_error, gebe den richtigen String an'
        )
        sleep(3)
        exit()
    if question == 't2m':
        charset = r'[a-z0-9.,]'
        text_in = input(
            f'\tDen zu übersetzenden Text hier eingeben '
            f'(chars: "a-z", "0-9" "," "."\t"exit" to quit)\n\n>>>\t'
        )
        if match(charset, text_in):
            text = '  '.join(text_in)
            translation_code = text.maketrans(morsecode)
            translation = text.translate(translation_code)
            print(
                f'\t{translation}\n'
            )
        else:
            print(
                '\tvalue_error, falsches Zeichen angegeben'
            )
            sleep(3)
            exit()
    if question == 'm2t':
        charset = r'[.-e,x,i.t]'
        text_in = input(
            '\tDen zu übersetzenden Morsecode hier eingeben\n\tBuchstaben '
            'mit Space" " trennen und Wörter mit 2x Space"  " trennen\n'
            '\t(chars: "." = short "-" = long\t"exit" to quit)\n\n>>>\t'
        )
        if match(charset, text_in):
            out = []
            letter = []
            j = -1
            for i in text_in.split('  '):
                j += 1
                letter += [i.split(' ')]
                for k in range(len(letter[j])):
                    out += morsecode_reversed.get(letter[j][k],
                                              'Hier den Morsecode eingeben')
                out += ' '
            out = ''.join(out)
            print(
                f'\t{out}\n'
            )
        else:
            print(
                '\tvalue_error, falsches Zeichen angegeben'
            )
            sleep(3)
            exit()
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pad385: Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Konstanten werden per Konvention KOMPLETT_GROSS geschrieben.

`lst` ist ein schlechter Name. Das ist eine kryptische Abkürzung bei der man nicht weiss was sie bedeuten soll. ”List”? Kann ja eigentlich nicht sein, denn es wird keine Liste, sondern ein Tupel an den Namen gebunden. Schönes Beispiel warum konkrete Grunddatentypen nichts in Namen verloren haben. Zudem würde der Typ dem Leser auch gar nicht verraten was die beiden kryptischen Werte in dem Tupel bedeuten sollen. Das wird ja erst später im Code aufgelöst. Und es sollte kein Tupel sein, denn da bestimmt der Index an dem etwas steht, normalerweise was für eine Bedeutung der Wert hat. Hier haben aber alle Werte im Tupel die gleiche Bedeutung: Abkürzung für eine Umwandlungsrichtung.

Der Wert wird auch nur einmal verwendet. Da kann man ihn auch gleich dort hin schreiben, ohne vorher einen nichtssagenden Namen dafür zu definieren.

Ich sehe gerade nicht wie `text_in` am Anfang der Schleife den Wert 'exit' haben kann. Das ist auch eher ein Fall für eine ”Endlossschleife” die an der entsprechenden Stelle mit ``break`` oder ``return`` verlassen werden kann.

Es ist von der Benutzung her auch nicht ganz einzusehen warum man erst eine Kodierungsrichtung auswählen muss, bevor man 'exit' eingeben kann/darf. Das würde eher bei der allerersten Frage Sinn machen, also Richtung wählen oder abbrechen. Denn wenn man sich schon für eine Richtung entschieden hat, dann will man ja offensichtlich etwas Kodieren. Falls nicht, kann man die Eingabe dort auch einfach leer lassen um zur äusseren Schleife zurück zu gelangen.

Man könnte dem Benutzer aber auch einfach sagen, dass er das Programm jederzeit und egal wo mit Strg+C abbrechen kann.

Der Name `question` ist falsch, da es sich nicht um eine Frage, sondern um die Antwort des Benutzers handelt.

Statt vorab zu prüfen ob der Benutzer eine der beiden Antworten gegeben hat, würde man besser die Antworten mit ``if``/``elig`` abfragen und am Ende einen ``else``-Zweig hinzufügen in dem der Fall abgehandelt wird, dass der Benutzer eine ungültige Auswahl getroffen hat. Dann muss man 'm2t' und 't2m' auch nicht dreimal im Code stehen haben, sondern nur zweimal. Was auch noch einmal zu viel ist. Was man einfach lösen kann wenn man den Code zum Kodieren in Funktionen auslagert. Dann kann man nämlich ein Wörterbuch anlegen welches das Kürzel auf die jeweilige Funktion abbildet.

Wenn man die beiden Codeteile zum Kodieren in eigene Funktionen auslagert, wird die Hauptfunktion auch gleich viel übersichtlicher und weniger tief verschachtelt.

`exit()` sollte man nur verwenden wenn man auch tatsächlich einen Rückgabecode an den Aufrufer des Programms liefern will. Und das auch nicht an allen möglichen Stellen im Programm sondern da, wo das Programm auch auf ”natürliche Weise” enden würde. Ansonsten sieht das nach einem Hack aus um sich keine Gedanken über einen sauberen Programmablauf machen zu müssen.

Vor jedem `exit()` steht auch ein ``sleep(3)`` – was dann auch *einmal* an das ”natürliche” Ende gehört.

Beide Koderungen enden auf den gleichen Code im ``else``-Zweig. Das sollte man ausserhalb zusammenfassen.

`maketrans()` auf einer Zeichenkette aufzurufen ist verwirrend. Die gesamte Funktion kann man auch deutlich kompakter schreiben.

Was soll denn r'[.-e,x,i.t]' bitte sein? Das Komma und der Punkt sind zwei mal enthalten, es sind alle Zeichen zwischen '.' und dem kleinen 'e' enthalten, das soll ganz sicher nicht so sein. Und man kann Beispielsweise auch 'xiet', 'itxe' oder jede andere Buchstabenkombination eingeben die 'e', 'i', 't', und 'x' enthalten, inklusive mehrfachvorkommen von Buchstaben. Und Kommas dürfen auch enthalten sein. Was weder Teil von Morsecode noch vom Wort 'exit' wäre.

Ausserdem fehlt das Leerzeichen. Warum das bisher scheinbar funktioniert? Ganz einfach: weil in der Eingabe alles mögliche stehen darf solange mindestens ein Zeichen am Anfang steht auf den der reguläre Ausdruck matcht. Wenn man *alle* Zeichen der Eingabe testen möchte muss man a) sagen das sich die Zeichenklasse beliebig oft wiederholen muss/darf und b) dass das auch tatsächlich bis zum Ende der Zeichenkette passen muss, und nicht nur für einen Präfix. Das gilt auch für den regulären Ausdruck in bei der anderen Richtung.

Das Dekodieren des Morecodes ist komisch bis verwirrend. Ich weiss nicht was dieser komplizierte Code mit dem `j` und der `letter`-Liste soll. Das erfüllt keinen sinnvollen Zweck.

Ungetesteter Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
from re import match
from time import sleep

MORSE_CODE = {
    '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': '--..', 
    '0': '-----', 
    '1': '.----', 
    '2': '..---', 
    '3': '...--', 
    '4': '....-', 
    '5': '.....', 
    '6': '-....', 
    '7': '--...', 
    '8': '---..', 
    '9': '----.', 
    '.': '.-.-.-', 
    ',': '--..--'
}
MORSE_CODE_REVERSED = {
    morse_code: character for character, morse_code in MORSE_CODE.items()
}


def do_convert_text_to_morse_code():
    text = input(
        f'\tDen zu übersetzenden Text hier eingeben '
        f'(chars: "a-z", "0-9" "," ".")\n\n>>>\t'
    )
    if match(r'[a-z0-9,. ]*$', text):
        morse_code = '  '.join(text.translate(str.maketrans(MORSE_CODE)))
        print(f'\t{morse_code}\n')
        return True
    else:
        return False


def do_convert_morse_code_to_text():
    charset = r'[-. ]*$'
    morse_code = input(
        '\tDen zu übersetzenden Morsecode hier eingeben\n'
        '\tBuchstaben mit Space " " trennen und Wörter mit 2x Space "  "'
        ' trennen\n'
        '\t(chars: "." = short "-" = long)\n\n>>>\t'
    )
    if match(charset, morse_code):
        characters = list()
        for morse_word in morse_code.split('  '):
            for morse_character in morse_word.split(' '):
                character = MORSE_CODE_REVERSED.get(morse_character)
                if character:
                    characters.append(character)
                else:
                    characters.append(f'[{morse_character}]')
            characters.append(' ')
        print(f'\t{"".join(characters)}\n')
        return True
    else:
        return False


def main():
    answer2function = {
        'm2t': do_convert_morse_code_to_text,
        't2m': do_convert_text_to_morse_code,
    }
    print('\tHerzlich Willkommen!\n\tMorsecode Translator v2.0\tAutor: Pad')
    try:
        while True:
            answer = input(
                f'\tVon Morsecode zu Text oder von Text zu Morsecode?'
                f' ({"/".join(answer2function)}): '
            )
            do_convert = answer2function.get(answer)
            if do_convert:
                if not do_convert():
                    print('\tUngültige Eingabe!')
                    break
            else:
                print('\tUngültige Eingabe!')
                break
        sleep(3)
    except KeyboardInterrupt:
        pass  # Intentionally ignored.


if __name__ == '__main__':
    main()
Nächster Schritt (eigentlich das allererste was man hätte machen sollen, schon bein schreiben des Programms) wäre das trennen von Programmlogik und Benutzerinteraktion, so dass man die Kodierungen automatisiert testen kann.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Pad385
User
Beiträge: 39
Registriert: Dienstag 12. März 2019, 18:33

das ich dich auch richtig verstehe das heißt ja aus den funktionen die inputs raus holen und in die main funktion schreiben? ne ich weis nicht wie ich es trennen soll print input alles in die main funktion ? und nur die übersetztungen in zwei funktionen ?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pad385: was braucht eine Funktion, die Text in Morse-Code übersetzen soll? Den Text. Und was liefert sie zurück? Die Morse-Zeichen. Also brauchst Du eine Funktion mit einem Argument und einem passenden Rückgabewert.
Pad385
User
Beiträge: 39
Registriert: Dienstag 12. März 2019, 18:33

ich hab mal angefangen zu schreiben aber die zeit wird knapp sieht das besser aus oder wird das nicht funktionieren ?
habs noch nicht getestet wie auch bin nicht fertig^^
edit: am ende hab ich schon n fehler gemacht...

Code: Alles auswählen

#!/usr/bin/env python3
from re import match
from time import sleep

MORSE_CODE = {
    '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': '--..', 
    '0': '-----', 
    '1': '.----', 
    '2': '..---', 
    '3': '...--', 
    '4': '....-', 
    '5': '.....', 
    '6': '-....', 
    '7': '--...', 
    '8': '---..', 
    '9': '----.', 
    '.': '.-.-.-', 
    ',': '--..--'
}
MORSE_CODE_REVERSED = {
    morse_code:character for character, morse_code in MORSE_CODE.items()
}

def convert_text_to_morse(text):
    text = ' '.join(text_in)
    translation_code = text.maketrans(MORSE_CODE)
    translation = text.translate(translation_code)
    return translation

def convert_morse_to_text(morse)
    characters = list()
    for morse_word in text.split('  '):
        for morse_character in morse_word.split(' '):
            character = MORSE_CODE_REVERSED.get(morse_character)
            if character:
                characters.append(' ')
            else:
                characters.append(f'[{morse_character}]')
            characters.append(' ')
        out = ''.join(characters)
    return out

    
def main():
    answer2function = {
        'm2t': convert_morse_to_text,
        't2m': convert_text_to_morse
    }
    print(
        f'\tHerzlich Willkommen!\n\tMorsecode Translator v2.0\tAutor: Pad'
        f'\t\t\t"STRG+C" to quit'
    )
    try:
        while True:
            answer = input(
                f'\tVon Morsecode zu Text oder von Text zu Morsecode? '
                f'({"/".join(answer2function)}) : '
            )
            if answer = 't2m':
                charset = r'[a-z0-9., ]*$'
                text_in = input(
                    f'\tDen zu übersetzenden Text hier eingeben '
                    f'(chars: "a-z", "0-9" "," ".")\n\n>>>\t'
                )
                if match(charset, text_in):
                    out = convert_morse_to_text(text_in)
                    print(out)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

In `convert_text_to_morse` gibt es kein `text_in`. Warum hängst Du in `convert_morse_to_text` nur Leerzeichen aneinander. Außerdem passt da was mit den Einrückungen nicht.
Ganz unten fehlt dann noch was, mindestens der except-Block, was auch immer da für eine Ausnahme auftreten soll.
Antworten