Seite 1 von 2

leet-speak

Verfasst: Freitag 7. Januar 2011, 13:17
von Xynon1
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 ?

Re: leet-speak

Verfasst: Samstag 8. Januar 2011, 15:01
von Dauerbaustelle
Ginge sowas nicht vielleicht mit ``str.translate``?

Re: leet-speak

Verfasst: Samstag 8. Januar 2011, 21:13
von 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.

Re: leet-speak

Verfasst: Montag 10. Januar 2011, 08:56
von Xynon1
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

Re: leet-speak

Verfasst: Dienstag 11. Januar 2011, 19:00
von DaMutz
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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 08:50
von Xynon1
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 ?)

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 09:48
von snafu
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. ;)

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 10:10
von Xynon1
:) - 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

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 11:35
von snafu
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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 11:41
von Xynon1
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

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 11:49
von EyDu
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())

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 12:02
von Xynon1
Uh, das ist gut, die "get"-Methode kommt hier wirklich schön zur Geltung, danke.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 14:43
von Xynon1
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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 15:09
von 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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 15:38
von Xynon1
@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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 16:33
von Xynon1
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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 17:31
von Leonidas
``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.

Re: leet-speak

Verfasst: Mittwoch 12. Januar 2011, 17:32
von 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.

Re: leet-speak

Verfasst: Donnerstag 13. Januar 2011, 11:52
von Xynon1
@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)))

Re: leet-speak

Verfasst: Donnerstag 13. Januar 2011, 12:55
von Leonidas
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 :)