leet-speak

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hatte gestern Abend mal eine halbe Stunde langeweile und war bis jetzt am überlegen ob ich das überhaupt posten soll, aber vieleicht hat ja mal jemand von euch Interesse drüber zu schauen :D
Handelt sich lediglich um einen kleinen Übersetzer, wie der Title schon vermuten lässt.

Code: Alles auswählen

#!/usr/bin/env python
import random

LEET_ENCODE = {
    "A" : ("A", "a", "4", "@", "/-\\", "/\\", "^", "ci"),
    "B" : ("B", "b", "8", "|3", "6", "13", "\xdf", "]3", "I3"),
    "C" : ("C", "c", "(", "<", "\xa2", "{", "\xa9"),
    "D" : ("D", "d", "|)", "I)", "|>", "I>", "]>", "[>", "cl", "cI"),
    "E" : ("E", "e", "3", "\x80", "&", "[-"),
    "F" : ("F", "f", "|=", "I=", "}", "]=", "(=", ")="),
    "G" : ("G", "g", "6", "9", "(_+", "cj"),
    "H" : ("H", "h", "|-|", "#", "]-[", "[-]", ")-(", "(-)", ":-:" "}{", "}-{"),
    "I" : ("I", "i", "1", "!", "|", ";"),
    "J" : ("J", "j", "_|", "_/", "]", "\xbf", "</", "_)"),
    "K" : ("K", "k", "X", "|<", "I<", "]<", "|X", "|{"),
    "L" : ("L", "l", "|", "|_", "\xa3", "1", "7", "\xac"),
    "M" : ("M", "m", "|V|", "|v|", "/\\/\\", "|\\/|", "^^", "nn", "(V)", "(v)",
           "(\\/)", "/|\\", "/|/|", ".\\\\", "/^^\\", "/V\\", "|^^|"),
    "N" : ("N", "n", "|\|", "/|/", "]\\[", "//"),
    "O" : ("O", "o", "0", "()", "[]", "\xa4", "<>", "@"),
    "P" : ("P", "p", "|o", "|*", "\xb0", "|>", "|?", "|7", "q", "\xfe", "\xb6"),
    "Q" : ("Q", "q", "p", "O_", "0,", "(,)", "9", "\xb6", "O,"),
    "R" : ("R", "r", "|2", "/2", "I2", "I^", "|^", "lz", "Iz", "|z", "l2"),
    "S" : ("S", "s", "Z", "z", "5", "$", "\xa7"),
    "T" : ("T", "t", "7", "+", "-|-", "1", "\x86"),
    "U" : ("U", "u", "|_|", "(_)", "\\_/", "\\_\\", "/_/", "]_[", "\xb5"),
    "V" : ("V", "v", "\\/"),
    "W" : ("W", "w", "\\/\\/", "vv", "VV", "uu", "UU", "'//", "\\\\'", "\\^/",
           "(n)", "\\X/", "\\|/", "\\_|_/", "\\_:_/"),
    "X" : ("X", "x", "><", "}{", "*", ")("),
    "Y" : ("Y", "y", "\xa5", "\xd7", "j", "`/", "\xff"),
    "Z" : ("Z", "z", "2", "~/_", "7_", "%")
    }

LEET_LENGTH = 5
LEET_DECODE = dict()
for key, values in LEET_ENCODE.iteritems():
    for value in values:
        LEET_DECODE[value] = key

def encode(text):
    leet = []
    for char in text:
        try:
            leet.append(random.choice(LEET_ENCODE[char.upper()]))
        except KeyError:
            leet.append(char)
    return "".join(leet)

def decode(leet):
    text = []
    index = 0
    while index < len(leet):
        for size in xrange(LEET_LENGTH):
            chunksize = LEET_LENGTH - size
            chars = leet[index:index + chunksize]
            if chars in LEET_DECODE:
                text.append(LEET_DECODE[chars])
                break
            elif chunksize == 1:
                text.append(chars)
        index += chunksize
    return "".join(text)
Das die Rückumwandlung nicht völlig gelingt ist mir klar, allein schon weil in der Decode Dictionary einige Keys verworfen werden, da sie doppelt drin stehen, zudem gehe ich beim dekodieren nur Vergleichend vor.
Genaugenommen prüfe ich ob die längst Zeichenkette ein Buchstabe existiert und dann werde ich kleiner, damit habe ich aber einfach nur eine "hohe" Warscheinlichkeit das es zumindest Lesbar wird :wink:

Andere Ansätze, Ideen oder Verbesserungen ?
Zuletzt geändert von Xynon1 am Mittwoch 12. Januar 2011, 10:25, insgesamt 3-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Ginge sowas nicht vielleicht mit ``str.translate``?
BlackJack

@Dauerbaustelle: Es wird für jedes Zeichen zufällig eine aus mehreren Alternativen ausgewählt und die können auch länger als ein Zeichen sein. `str.translate()` ist da zu "statisch" und zumindest bei Python <3 kann man ein Zeichen auch wieder nur durch ein Zeichen, und nicht mehrere, ersetzen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Deswegen habe ich ja auch Listen genommen und sie mit "join" wieder zusammengefügt, aber hat keiner von euch "Andere Ansätze, Ideen oder Verbesserungen ?".
Sonst seit ihr doch immer so schnell mit dem zerlegen von Quelltexten :D
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

benutze doch :)

Code: Alles auswählen

if __name__ == '__main__':
diese Stelle gefällt mir auch nicht so:

Code: Alles auswählen

for size in xrange(LEET_LENGTH):
    chunksize = LEET_LENGTH - size
ich würde eher zurück zählen als hoch zu zählen und zu subtrahieren. Ich fände es besser lesbar, was genau gemacht wird, ausserdem wird 'size' sonst nicht benutzt.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Stimmt das mit dem vorwärts zählen ist nicht so clever, ich habe es oben mal geändert.
und "if __name__ == '__main__':" existiert in meinem Programm natürlich, um es auch im Terminal direkt nutzen zu können, habe ich auch oben ergänzt. (Ich denke nicht das sich hierfür ein "optparse"r lohnt, oder ?)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Na, die letzten 2 Zeilen in deinem hinzugefügten `if __name__ == '__main__'`-Block sind jetzt aber nicht so schön. Statt dem blanken `except: pass`, was vermutlich einen `IndexError` vermeiden soll, wenn kein Argument mitgegeben wird, solltest du lieber speziell diese Ausnahme abfangen oder auf die Anzahl der übergebenen Argumente testen.

Im Übrigen schadet es zwecks besserer Nachvollziehbarkeit nicht, wenn du neuem Code auch einen neuen Post gönnst, den du bedarfsweise natürlich auslagern kannst. ;)
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

:) - Ich weiß das der unter Teil nicht schön ist, dewegen hatte ich ihn ja raus gelassen, das war eigentlich nur für mich um es mal schnell nutzen zu können.
Da habe ich nicht mal Nachgedacht, wie man an dem offensichtlichen "except: pass" sehen kann.

Edit: Habe oben nochmal den orginal Post hingestellt und hier den neuen:

Code: Alles auswählen

#!/usr/bin/env python
import random
import sys

LEET_ENCODE = {
    "A" : ("A", "a", "4", "@", "/-\\", "/\\", "^", "ci"),
    "B" : ("B", "b", "8", "|3", "6", "13", "\xdf", "]3", "I3"),
    "C" : ("C", "c", "(", "<", "\xa2", "{", "\xa9"),
    "D" : ("D", "d", "|)", "I)", "|>", "I>", "]>", "[>", "cl", "cI"),
    "E" : ("E", "e", "3", "\x80", "&", "[-"),
    "F" : ("F", "f", "|=", "I=", "}", "]=", "(=", ")="),
    "G" : ("G", "g", "6", "9", "(_+", "cj"),
    "H" : ("H", "h", "|-|", "#", "]-[", "[-]", ")-(", "(-)", ":-:" "}{", "}-{"),
    "I" : ("I", "i", "1", "!", "|", ";"),
    "J" : ("J", "j", "_|", "_/", "]", "\xbf", "</", "_)"),
    "K" : ("K", "k", "X", "|<", "I<", "]<", "|X", "|{"),
    "L" : ("L", "l", "|", "|_", "\xa3", "1", "7", "\xac"),
    "M" : ("M", "m", "|V|", "|v|", "/\\/\\", "|\\/|", "^^", "nn", "(V)", "(v)",
           "(\\/)", "/|\\", "/|/|", ".\\\\", "/^^\\", "/V\\", "|^^|"),
    "N" : ("N", "n", "|\|", "/|/", "]\\[", "//"),
    "O" : ("O", "o", "0", "()", "[]", "\xa4", "<>", "@"),
    "P" : ("P", "p", "|o", "|*", "\xb0", "|>", "|?", "|7", "q", "\xfe", "\xb6"),
    "Q" : ("Q", "q", "p", "O_", "0,", "(,)", "9", "\xb6", "O,"),
    "R" : ("R", "r", "|2", "/2", "I2", "I^", "|^", "lz", "Iz", "|z", "l2"),
    "S" : ("S", "s", "Z", "z", "5", "$", "\xa7"),
    "T" : ("T", "t", "7", "+", "-|-", "1", "\x86"),
    "U" : ("U", "u", "|_|", "(_)", "\\_/", "\\_\\", "/_/", "]_[", "\xb5"),
    "V" : ("V", "v", "\\/"),
    "W" : ("W", "w", "\\/\\/", "vv", "VV", "uu", "UU", "'//", "\\\\'", "\\^/",
           "(n)", "\\X/", "\\|/", "\\_|_/", "\\_:_/"),
    "X" : ("X", "x", "><", "}{", "*", ")("),
    "Y" : ("Y", "y", "\xa5", "\xd7", "j", "`/", "\xff"),
    "Z" : ("Z", "z", "2", "~/_", "7_", "%")
    }

LEET_LENGTH = 5
LEET_DECODE = dict()
for key, values in LEET_ENCODE.iteritems():
    for value in values:
        LEET_DECODE[value] = key

def encode(text):
    leet = []
    for char in text:
        try:
            leet.append(random.choice(LEET_ENCODE[char.upper()]))
        except KeyError:
            leet.append(char)
    return "".join(leet)

def decode(leet):
    text = []
    index = 0
    while index < len(leet):
        for chunksize in xrange(LEET_LENGTH, 0, -1):
            chars = leet[index:index + chunksize]
            if chars in LEET_DECODE:
                text.append(LEET_DECODE[chars])
                break
            elif chunksize == 1:
                text.append(chars)
        index += chunksize
    return "".join(text)

if __name__ == "__main__":
    try:
        if sys.argv[1] == "decode":
            print(decode(sys.argv[2]))
        elif sys.argv[1] == "encode":
            print(encode(sys.argv[2]))
        else:
            print("Bitte die Syntax 'python leet.py [encode/decode] [text]' " \
                  "nutzen.")
    except IndexError:
        pass
Zuletzt geändert von Xynon1 am Mittwoch 12. Januar 2011, 16:56, insgesamt 1-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn ein Programm zwingend zusätzliche Argumente erwartet, aber keine bekommt, dann sollte es für gewöhnlich eine Fehlermeldung zur Benutzung ausgeben. Bei dir kommt diese Meldung nur, wenn eine unbekannte Option genutzt werden soll. Wird das Programm bei dir "nackt" aufgerufen, passiert gar nichts. Nichts für ungut, aber vielleicht willst du dir doch mal besser `argsparse` anschauen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich wollte mir eigentlich "optparse" genauer ansehen, ich habe es aber hier noch nicht für Notwendig empfunden. Aber recht hast du natürlich nur habe ich das bisher noch nie wirklich benötigt.
Wo ist denn eigentlich der entscheidende Unterschied zwischen den beiden?
Edit: Ok, habe es schon http://argparse.googlecode.com/svn/trun ... parse.html
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

encode hat auch noch Potential:

Code: Alles auswählen

def encode(text):
    return "".join(random.choice(LEET_ENCODE.get(c, c)) for c in text.upper())
Das Leben ist wie ein Tennisball.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Uh, das ist gut, die "get"-Methode kommt hier wirklich schön zur Geltung, danke.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich habe da noch ein paar kleine Schwierigkeiten mit "argparse". Also, sofort schreihen, wenn ich hier was falsch nutze. So sieht es im Moment aus:

Code: Alles auswählen

if __name__ == "__main__":
    parser = ArgumentParser(prog="leet.py",
                            description="Ein leet \xdcbersetzer.")
    parser.add_argument("-e", "--encode", type=str, nargs="?", dest="encodetext",
                        action="store", help="Kodiert einen Text.")
    parser.add_argument("-d", "--decode", type=str, nargs="?", dest="decodetext",
                        action="store", help="Dekodiert einen Text")
    parser.add_argument("-v", "--version", action="version",
                        version="{0} {1}".format(parser.prog, __version__))

    result = parser.parse_args()
    if result.encodetext is not None:
        print(encode(result.encodetext))
    elif result.decodetext is not None:
        print(decode(result.decodetext))
    else:
        parser.print_help()
Mein 1. Problem ist, wie bekomme ich "encode" und "decode" so hin, das ich nur eines von beiden wählen kann, bzw geht das überhaupt ?, so wird "decode" halt einfach ignoriert.
2. Problem ist ein Schönheitsfehler, wie bekomme ich die Optionen "encode" und "decode" so hin, dass die wie die Optionen "help" und "version" aussehen. So sieht es einfach unschön aus.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Ich würde "encode"/"decode" nicht als Optionen anbieten, denn es sind ja gar keine. *Optionen* sind IMHO *optional*. Ob man en- oder dekodieren will, *muss* man ja aber angeben. Und auch der Eingabetext selber gehört IMHO nicht zu den Optionen. Den würde ich gar nicht über die Kommandozeile angeben, sondern auf `stdin` erwarten, wie man das -- zumindest unter Unix -- von solchen Programmen gewohnt ist. Das ist doch viel angenehmer zu benutzen als den Text an der Kommandozeile einzugeben, wo man ihn noch vor der Shell "schützen" muss. Und bei dem Leet-Speak kommen ja sogar einige Zeichen vor, die man unbedingt vor der Shell schützen muss.

Wenn `--encode`/`--decode` Optionen sein sollen, dann sollte `--encode` der Default sein und beide sollten auf das gleiche Boolean-Flag wirken, was eben aussagt, ob en- oder dekodiert werden soll.

Muss man bei `argparse` selbst eine Option für die Version erstellen? Und `-v` ist bei sehr vielen Programmen die Abkürzung für eine `--verbose`-Option.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@BlackJack
Das seh ich ja auch so, nur mit den Positionalen Argumenten mit Multichoice kam ich nicht klar deswegen ja auch die Nachfrage, habe aber gerade gefunden wie es funktioniert "subparser" ist das richtige Stichworthttp://www.doughellmann.com/PyMOTW/argp ... ng-parsers

ja version ist nicht automatisch, aber das "-v" muss nicht sein.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

So jetzt sieht es so aus

Code: Alles auswählen

if __name__ == "__main__":
    parser = ArgumentParser(prog="leet.py",
                            description="Ein leet \xdcbersetzer.")
    subparsers = parser.add_subparsers(help="Befehle")
    
    encodeparser = subparsers.add_parser("encode", help="Kodiert einen Text.")
    encodeparser.add_argument("encodetext", type=str, nargs="?", action="store", 
                              help="Der Text, welcher kodiert werden soll.")
    
    decodeparser = subparsers.add_parser("decode", help="Dekodiert einen Text.")
    decodeparser.add_argument("decodetext", type=str, nargs="?", action="store", 
                              help="Der Text, welcher dekodiert werden soll.")
     
    parser.add_argument("--version", action="version",
                        version="{0} {1}".format(parser.prog, __version__))

    result = parser.parse_args()
    try:
        print(encode(result.encodetext))
    except AttributeError:
        try:
            print(decode(result.decodetext))
        except AttributeError:
            parser.print_help()
Ist aber auch nicht so schön, wer kann mich mal aufklären, wie das üblicherweise beim argparser ausgewertet wird, denn da findet man in den Documentationen nicht viel.

Was die Sache "Shell schützen" angeht, verstehe ich zwar was du meinst, aber ich habe keine Ahnung wie man das angehen soll? Kannst du mir da mal einen Anstoß geben.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

``raw_input`` und auf leere Zeile warten... oder, vielleicht besser, EOF.

Ich persönlich würde nur eine ``--decode`` Option angeben, ``--encode`` zum default machen. Also quasi sowas was ``gzip`` auch macht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@Xynon1: Wieso willst Du den Text unbedingt als Argument zu der Option!? Das ist doch total umständlich. Warum nicht diese beiden Optionen als *ein* Flag, das angibt ob der andere Kram auf der Kommandozeile nun en- oder dekodiert werden soll!? Wenn man Optionen parst, heisst das doch nicht, dass man keine normalen Argumente mehr verwenden darf.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@BlackJack
war reiner Übungszweck.

So, wenn ich Leonidas richtig verstanden habe, sollte das Programm einfach aufgerufen werden (eventuell mit --decode als option) und den Rest dann das python Programm machen lassen.
Also so:

Code: Alles auswählen

if __name__ == "__main__":
    parser = ArgumentParser(prog="leet.py",
                            description="Ein leet \xdcbersetzer.")
    parser.add_argument("-d", "--decode", dest="decode", action="store_true",
                        help="Dekodiert einen Text")
    parser.add_argument("--version", action="version",
                        version="{0} {1}".format(parser.prog, __version__))

    result = parser.parse_args()
    if result.decode:
        text = raw_input("Kodierter Text: ")
        print("Dekodierter Text: {0}".format(decode(text)))
    else:
        text = raw_input("Dekodierter Text: ")
        print("Kodierter Text: {0}".format(encode(text)))
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich würde wohl von ``sys.stdin`` lesen und dann in (der Konsistenz wegen) in ``sys.stdout`` schreiben, ohne dass was zusätzlich ausgegeben wird, so dass ``deinprog < klartext | deinprog -d `` wieder genau den selben Inhalt hat wie die Eingabe. Also round-trip-kompatibel :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten