Strings fluchten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Donnerstag 31. Januar 2008, 14:15

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Donnerstag 31. Januar 2008, 16:51

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.
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Donnerstag 31. Januar 2008, 22:53

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Freitag 1. Februar 2008, 11:19

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', '\\' : '\\'})
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Freitag 1. Februar 2008, 12:37

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Freitag 1. Februar 2008, 13:00

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Freitag 1. Februar 2008, 13:52

Ich denke hier käme man mit relativ einfachen regulären Ausdrücken mit weniger Code aus.
Benutzeravatar
Michael Schneider
User
Beiträge: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Montag 4. Februar 2008, 13:18

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Montag 4. Februar 2008, 14:37

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)
Antworten