Seite 1 von 2

Verfasst: Donnerstag 31. Januar 2008, 14:15
von Michael Schneider
keppla hat geschrieben:
Michael Schneider hat geschrieben:Unter Python2.2 habe ich nur:
raw_unicode_escape.py
unicode_escape.py
Damit wird das Ergebnis zwar beim Dekodieren in einen Unicode-String umgewandelt, aber mit str bekomme ich das Original wieder.
musst das ganze auch decodieren:

Code: Alles auswählen

x = "Hail Eris!\nAll Hail Discordia!"
assert x == x.encode("string_escape").decode("string_escape")
Hi Keppla,

was meinst Du damit?
Erstens habe ich kein "string_escape" codec (habe bei dem obigen Suchergebnis nach allen Dateien gesucht, die "escape" enthalten).
Zweitens bringt es mir nichts, den String zu codieren und gleich wieder zu dekodieren. Ich muss ihn doch zwischendurch noch senden/bearbeiten/speihern, oder? Ich habe Dich bestimmt falsch verstanden.

Michael

Verfasst: Donnerstag 31. Januar 2008, 16:51
von keppla
Sorry, vergiss mein Post, ich hatte das "Python 2.2" völlig übersehen, und dich irgendwie ganz anders verstanden. Bin scheinbar nicht gerade auf der höhe.
Erstens habe ich kein "string_escape" codec (habe bei dem obigen Suchergebnis nach allen Dateien gesucht, die "escape" enthalten).
Hatte ich übersehen.
Zweitens bringt es mir nichts, den String zu codieren und gleich wieder zu dekodieren.
Damit wollte ich die symmetrie der zwei funktionen verdeutlichen, in der Fehlannahme, dass du das mit irgendwelchen scripts lösen wolltest. Wie gesagt, is heut nicht mein tag.

Also, mal etwas produktiver:
mit codec.register kann man sich "eigene" codecs registrieren. Eine mögliche lösung wäre, wenn der "string_encode" in python geschrieben ist, diesen teil aus python2.5 zu kopieren (unter Beachtung der Lizenz versteht sich), ihn zu registrieren, und mitzuverteilen.

Verfasst: Donnerstag 31. Januar 2008, 22:53
von Michael Schneider
keppla hat geschrieben: Also, mal etwas produktiver:
mit codec.register kann man sich "eigene" codecs registrieren. Eine mögliche lösung wäre, wenn der "string_encode" in python geschrieben ist, diesen teil aus python2.5 zu kopieren (unter Beachtung der Lizenz versteht sich), ihn zu registrieren, und mitzuverteilen.
Hi Keppla,

daran habe ich auch schon gedacht und wollte fragen, ob mir jemand dieses string-codec Modul posten kann. Aber wie es aussieht, sind die wrapper.py Dateien mit "escape" im Namen (oben) nur Wrapper für C-Funktionen. Daher denke ich, dass das auch für den string_escape codec gilt.

Aber mit dem unicode_escape fahre ich ja ganz gut, das ist vielleicht sogar noch etwas sicherer, was Umlaute betrifft.

Gruß,
Michael

Verfasst: Freitag 1. Februar 2008, 11:19
von keppla
Michael Schneider hat geschrieben:Aber mit dem unicode_escape fahre ich ja ganz gut, das ist vielleicht sogar noch etwas sicherer, was Umlaute betrifft.
Wenn ich dein vorhaben richtig verstehe, dürften die doch keine probleme machen können.
Ob umlaute richtig verstanden werden ist ja eher eine frage, ob sender und empfänger sich auf ein encoding geeinigt haben (was bei dir ja zwangsläufig ist, da du beide Programmierst).

Wenn ich dein Protokoll richtig verstehe, möchtest du "token" senden, trennzeichen wäre \n.
Womit klar wäre: \n ist dein einziges steuerzeichen, du musst also nur dieses escapen.

So einen codec selbst zu schreiben ist imho nicht so schwer.

edit: um mal meinen Worten taten folgen zu lassen:

Code: Alles auswählen

def decode(s, escape, trans):
    chunks = []
        
    left = 0
    while True:        
        right = s.find(escape, left)
        if right == -1:
            chunks.append(s[left:])
            break
        else:
            chunk = s[left:right] + trans[s[right + 1]]
            chunks.append(chunk)
            left = right + 2
            
    return ''.join(chunks)
            
message = r"Hail Eris!\nAll Hail Discordia!\n\\ <- this is a backslash"
    
print message
print decode(message, '\\', {'n' : '\n', '\\' : '\\'})

Verfasst: Freitag 1. Februar 2008, 12:37
von Michael Schneider
keppla hat geschrieben:So einen codec selbst zu schreiben ist imho nicht so schwer.
Hi,

wie ich eingangs schrieb, habe ich das auch selbst schon implementiert. Aber dabei kam ich auf meine grundsätzliche escape/unescape Frage.

Schönes Wochenende,
Michel

Verfasst: Freitag 1. Februar 2008, 13:00
von Michael Schneider
Hier ist mal mein Ansatz für beliebige Esc-Sequenzen:

Code: Alles auswählen

esc_list = [("\\", "\\\\"), ("\n", r"\n")]

def escape(s, esc_list=esc_list):
    "Escape s with chars from list esc_list where val0=char, val1=esc_sequence"
    for key, esc_seq in esc_list:
        s = s.replace(key, esc_seq)
    return s
        
def unescape(s, esc_list=esc_list):
    "Unescape s with chars from list esc_list where val0=char, val1=esc_sequence"
    chunks = s.split("\\\\")
    for chunk_id in xrange(len(chunks)):
        for key, esc_seq in esc_list:
            if key == "\\": continue
            chunks[chunk_id] = chunks[chunk_id].replace(esc_seq, key)
    return "\\".join(chunks)
    
def test():
    original = "hallo\nwelt\!"
    print "original:         ", list(original), len(original)
    esc = escape(original)
    print "escaped:          ",list(esc), len(esc)
    unesc = unescape(esc)
    print "unescaped (orig.):", list(unesc), len(unesc)
		
if __name__ == "__main__":
    test()
Wenn man sich auf lf beschränkt, kann man die Funktionen natürlich noch verkürzen.

Gruß,
Michel

Verfasst: Freitag 1. Februar 2008, 13:52
von BlackJack
Ich denke hier käme man mit relativ einfachen regulären Ausdrücken mit weniger Code aus.

Verfasst: Montag 4. Februar 2008, 13:18
von Michael Schneider
BlackJack hat geschrieben:Ich denke hier käme man mit relativ einfachen regulären Ausdrücken mit weniger Code aus.
Hi Blackjack,

meine Versuche mit RE scheiterten daran, dass die Backslash- und anderen Escape-Sequenzen in einem Durchgang umgewandelt werden mussten, damit beispielsweise ein beim ersten Durchgang entstandener Backslash nicht mit einem zufällig folgenden 'n' verknüpft wird. Allenfalls könnte man für alle Escape-sequenzen prüfen, ob ihnen eine gerade Anzahl Backslashes vorausgeht.

Wie würdest Du des denn mit RE lösen? Bekommt man die gesamte Konvertierung in einen Durchlauf?

Grüße,
Michel

Verfasst: Montag 4. Februar 2008, 14:37
von BlackJack
Es ist doch nicht weniger Code geworden, weil die regulären Ausdrücke erst aus den Argumenten zusammen gesetzt werden müssen. Es kommt aber in beide Richtungen mit einer einzigen Ersetzung aus:

Code: Alles auswählen

import re

ESCAPE_CHAR = '\\'
ESCAPES = [('\n', 'n')]

def escape(s, escapes=ESCAPES, escape_char=ESCAPE_CHAR):
    to_escape = dict(escapes)
    to_escape[escape_char] = escape_char
    escape_re = re.compile('[%s]' % re.escape(''.join(to_escape.iterkeys())))
    return escape_re.sub(lambda m: escape_char + to_escape[m.group(0)], s)

def unescape(s, escapes=ESCAPES, escape_char=ESCAPE_CHAR):
    from_escape = dict((b, a) for a, b in escapes)
    from_escape[escape_char] = escape_char
    unescape_re = re.compile(re.escape(escape_char) + '(.)')
    return unescape_re.sub(lambda m: from_escape[m.group(1)], s)