Seite 1 von 1
Hilfe bei Umsetzung von String-/Listen-Operation
Verfasst: Donnerstag 14. Mai 2009, 11:15
von #cousin#
Hallo Zusammen,
ich sitze seit Tagen an einem Problem mit einem String und Operationen auf Diesem.
Die Liste besteht aus 8-Bit Binär Werten getrennt durch ein ";"
Code: Alles auswählen
10000110;01101000;01101110;01101000;01101110;01110010;01100000;10001010;01101000;10000010;10000110;10001100;10001010;
01110010;01100100;01100000;01101110;01100100;10000100;10000010;01100000;10000110;01100000;10000010;10000100;10000010;
10001010;01110010;10001100;01101110;10000100;01101110;01110010;10000110;01100000;10001010;
Ich möchte diese 8-Bit nun in 7-Bit Werte ändern, indem ich bei dem Ersten Block die erste Zahl abspalte und an das Ende des 2. Blockes anhänge. Bei dem 2. Block sollen dann die ersten beiden Zahlen abgespalten werden und an das Ende des 3. Blocks angehängt werden....usw....
in dem nachfolgenden Bild ist das Problem nochmal graphisch erklärt mit anderen Werten als den Obigen.
Ich stehe aktuell komplett auf dem Schlauch wie ich das am Besten in Python umsetze. Es wäre super, wenn mir Jemand von euch dabei helfen könnte.
Vielen Dank im Voraus!
Verfasst: Donnerstag 14. Mai 2009, 11:27
von EyDu
Zeig doch mal ein wenig Code oder beschreibe genauer, wo du Probleme bei der Umsetzung hast. Es hört sich sonst so an, als ob du fertigen Code von uns haben wolltest

Verfasst: Donnerstag 14. Mai 2009, 11:40
von webster
Was soll eigentlich mit Werten passieren, die an Position 8 und höher stehen? Da seh ich noch keine sinnvolle Fortsetzung.
Verfasst: Donnerstag 14. Mai 2009, 12:12
von HerrHagen
Code: Alles auswählen
>>> b = "10000110;01101000;01101110;01101000;01101110;01110010;01100000;10001010;"
>>> raw = b.replace(";", "")
>>> [raw[i:i+7] for i in range(0, len(raw), 7)]
['1000011', '0011010', '0001101', '1100110', '1000011', '0111001', '1100100', '1100000', '1000101', '0']
>>> [int(raw[i:i+7], 2) for i in range(0, len(raw), 7)]
[67, 26, 13, 102, 67, 57, 100, 96, 69, 0]
MFG HerrHagen
Verfasst: Donnerstag 14. Mai 2009, 13:20
von EyDu
@HerrHagen: Den Ansatz habe ich beim ersten Durchlesen auch vermutet, das ist aber nicht das gesuchte Ergebnis.
Verfasst: Donnerstag 14. Mai 2009, 14:35
von b.esser-wisser
Das scheint zu tun, was du willst:
Code: Alles auswählen
def recode_str(s, sep=";", prev=""):
"""WILL silently produce garbage with wrongly grouped strings"""
OUT_SIZE = 7
FILLER="" #to fill 8 'Bits'
#FILLER="0"
offset=len(prev)
res = []
for i, part in enumerate (s.split(sep)):
if part: # avoid empty parts
i_off = (i + offset) % (OUT_SIZE+1)
res.append(FILLER + part[i_off+1:] + prev)
prev = part[:i_off+1] if i_off < OUT_SIZE else ""
return ";".join(res), prev
Aber sag mir
bitte, dass du nicht irgendwo Zahlen oder Strings in diese Binär-strings verwandlest,
nur um sie wieder in Zahlen zu verwandeln - das geht mit , "&", ">>", "<<", etc. (und ggf. "ord()", "chr()") besser, logischer und schneller...
hth, Jörg
Verfasst: Donnerstag 14. Mai 2009, 14:39
von HerrHagen
Stimmt..., vielleicht in etwa so..?:
Code: Alles auswählen
>>> b = "11101000;00110010;10011011;11111101;01000110;11011001;11011001;"
>>> l = b.split(";")
>>> for i in range(len(l) - 1):
l[i+1] += l[i][:i+1]
l[i] = l[i][i+1:]
>>> l
['1101000', '1100101', '1101100', '1101100', '1101111', '0101000', '1110110', '1101100']
EDIT: Da war offensichtlich schon jemand schneller (und ausführlicher)
Verfasst: Freitag 15. Mai 2009, 11:11
von #cousin#
Hi Zusammen,
vielen Dank für die vielen Antworten.
Ich kann euch leider keine code-Fragmente posten, da ich schon ein Problem damit habe, wie ich das Ganze überhaupt angehe. Mir ist bewusst, dass ich dafür Schleifen benötige, aber schon bei dem Schleifenkopf harpert es.
@webster:
der 8. Wert entseht aus dem Teil vom 7. Wert der abgespalten wird und ab dem 9. Wert geht es wieder von Vorne los.
@b.esser-wisser:
am Ende läuft es darauf hinaus. Ich versuche das PDU encoding für SMS in Python zu implementieren und da ist es notwendig, die HEX-Werte in 8-Bit-inär zu wandeln, dann eben diese "Abspaltung" von Bits zu machen, und danach das Ganze dann wieder in HEX zu verwandeln und dann in ASCII. Am Ende habe ich dann aus dem gespeicherten HEX die orginal SMS wiederhergestellt.
@HerrHagen:
vielen Dank für das Code-Fragment. Ich werde es nun mal testen und schauen, was nach Position 7 passiert.
Verfasst: Freitag 15. Mai 2009, 11:38
von BlackJack
@#cousin#: Diese ganzen Zeichenkettenumwandlungen sind nicht nötig. Eine halbwegs vernünftige Lösung würde direkt auf den Bits operieren und nicht mit Zeichenketten mit verschiedenen Darstellungen von Zahlen in verschiedenen Basen arbeiten.
Der Schleifenkopf ist doch einfach: Du musst über die Oktette iterieren. Und dann in jedem Schritt etwas machen. Dabei musst Du Dir etwas aus dem jeweils vorherigen Schritt merken. Spiel das doch einfach mal auf dem Papier Schritt für Schritt durch.
Verfasst: Freitag 15. Mai 2009, 12:09
von b.esser-wisser
#cousin# hat geschrieben:Hi Zusammen,
@b.esser-wisser:
am Ende läuft es darauf hinaus. Ich versuche das PDU encoding für SMS in Python zu implementieren und da ist es notwendig, die HEX-Werte in 8-Bit-inär zu wandeln, dann eben diese "Abspaltung" von Bits zu machen, und danach das Ganze dann wieder in HEX zu verwandeln und dann in ASCII. Am Ende habe ich dann aus dem gespeicherten HEX die orginal SMS wiederhergestellt.
Das hatte ich befürchtet - die reine Pythonlösung wird aber recht hässlich:
Code: Alles auswählen
def cycle_with_offset(iterable, offset=0):
"""itertools.cycle faengt immer vorne an"""
cycler = it.cycle(iterable)
if offset:
for dummy in it.izip(xrange(offset), cycler):
pass # fast forward
return cycler
def recode_bytes(bytes, prev=0, offset=0):
OUT_BITS = 7
OUT_MASK = (1 << OUT_BITS) - 1
res = []
for i, value in it.izip(cycle_with_offset(xrange(OUT_BITS + 1), offset),
it.imap(ord,bytes)):
current_bits = OUT_MASK >> (i+1)
res.append(chr( ((value & current_bits) << i) | prev))
prev = ( value & ~ current_bits) >> (OUT_BITS - i)
return "".join(res), prev, i
hth, Jörg
Verfasst: Freitag 15. Mai 2009, 12:50
von BlackJack
Mein Versuch:
Code: Alles auswählen
def decode(bytes):
carry = 0
for i, byte in enumerate(bytes):
shift = i % 7
out, carry = ((byte << shift) | carry) & 0x7f, byte >> (7 - shift)
yield out
if shift == 6:
yield carry
carry = 0
Verfasst: Samstag 16. Mai 2009, 14:04
von #cousin#
Hi Zusammen,
ich habe das Ganze nun mal versucht in Python umzusetzen und es funktioniert auch, ab dem Punkt bei dem ich die Binärwerte habe. Allerdings ist in dem Teil vorher, indem ich von HEX nach Binär 8Bit umwandle vermutlich ein Fehler.
Könnt ihr euch das mal anschauen?
kompletter code:
Code: Alles auswählen
# decodes the PDU Message to a readable message
def pduSMS(smsMessage, path):
pdu_fobj = open(path + "/cuttedPieces_ASCII/pdu.ascii", "a")
# String to HEX
smsMessage = smsMessage.encode("hex")
# HEX -> BIN 8-bit
bin8sms = encodeToBin.b2b(16, 2, smsMessage)
# split BIN string in parts with length of 8 digits
part = ""
i = 0
k = 0
while k < len(bin8sms):
k = i + 8
for j in range(i, i+8):
if k < len(bin8sms):
part = part + bin8sms[j]
else:
rest = (len(bin8sms) % 8)
for m in range(i, i + rest):
part = part + bin8sms[m]
break
part = part + ";"
i = i+8
# BIN 8-bit -> BIN 7-bit
l = part.split(";")
for i in range(len(l) - 1):
l[i+1] += l[i][:i+1]
l[i] = l[i][i+1:]
bin7sms = str(l)
# BIN 7-bit -> DEC
i = 0
decsms = ""
while i < len(l):
if i <= len(l):
decsms = decsms + str(int(l[i], 2)) + ";"
i += 1
else:
break
# DEC -> ASCII
asciisms = ""
n = decsms.split(";")
for p in range(len(n) - 2):
char = int(n[p])
if char < 256:
asciisms = asciisms + chr(char) + ";"
pdu_fobj.write("ascii: " + asciisms + "\n")
pdu_fobj.close()
encodeToBin.py
Code: Alles auswählen
import string
# converts n in base r1 to base r2
def b2b(r1,r2,n): #Convert n in base r1 to base r2 and back
x = base(r1,r2,n)
return x
#This is the crown jewel of the routine where we use base 10 as a pivot to go from base r1 to r2.
def base(r1,r2,num):
digits=""
for j in range(0,10):
digits = digits + chr(j+48)
for j in range(10,36):
digits = digits + chr(j+55)
for j in range(36,52):
digits = digits + chr(j-4)
for j in range(52,59):
digits = digits + chr(j+6)
for j in range(59,224):
digits = digits + chr(j+32)
for j in range(224,256):
digits = digits + chr(j-224)
num1 = str(num)
ln = len(num1)
dec = 0
for j in range(ln):
# Get the ascii code of num
asci = string.index(digits,num1[j])
temp = r1**(ln-j-1)
# Convert the num in r1 to decimal
dec += asci*temp
# Init the storage string
RDX = ""
j=-1
dec2=dec
# get number of digits in decimal
while dec2:
dec2 = dec2 / r2
j = j+1
while j >= 0:
pwr = r2**j
Q = dec // pwr
dec = dec % pwr
RDX = RDX + digits[Q]
j-=1
return RDX
#
# modified from http://mail.python.org/pipermail/tutor/2003-August/024506.html
Verfasst: Samstag 16. Mai 2009, 14:40
von BlackJack
@#cousin#: OMG das wird ja immer gruseliger. Hör bitte mit diesen Zeichenkettenumwandlungen auf. Das ist ja nicht mit anzusehen.
Du brauchst eine Umwandlung von Zeichen zu Bytewert (`ord()`), dann eine Funktion, die auf diesen Werten die entsprechenden Bitoperationen ausführt und aus den 8-Bit-Werten die 7-Bit-Werte macht, und wieder eine Umwandlung nach Zeichen (`chr()`), das war's. Letzteres wahrscheinlich noch über eine Umsetzungstabelle, weil SMS soweit ich weiss eine relativ unübliche Kodierung verwendet.
Alleine wenn ich schon sehe wie Du die Darstellung zur Basis 2 in 8er-Blöcke aufteilst. Das geht mit einer einzigen "list comprehension" wesentlich einfacher. Aber wie gesagt, diese Umwege über verschiedene Zahlendarstellungen als Zeichenketten sind genau dass: *Umwege*!
Verfasst: Samstag 16. Mai 2009, 23:22
von #cousin#
Hi BlackJack,
ich geb dir vollkommen recht, dass der Code gruselig ist. Aber ich wusste mir nicht anders zu helfen. Der schlimmste Teil ist das Skript, welches is mir aus dem Netz gezogen habe um aus HEX die Binärwerte zu machen. Und ich glaube da liegt auch mein Fehler, warum das Ergebnis nicht stimmt.
zu deinen Anmerkungen:
-die Bitoperationen macht mein Skript dank HerrHagen ja und das sieht auch gut aus, bis auf den Rest den er immer noch als letztes Element speichert, aber den kann man getrost vergessen
-chr() verwende ich ja auch schon am Ende und soweit ich das verstanden habe, kann ich sogar den "normalen" chr nehmen, da die geheimnisvolle Kodierung durch das shiften in den Bits geschieht.
-ord() hier weiss ich leider nichts mit anzufangen....die Funktion liefert den int zu einem HEX-Wert, aber dann habe ich immernoch keine Binärdarstellung. Ich habe nun mal den Ansatz versucht, aber das Ergebnis passt immer noch nicht.
Code: Alles auswählen
import string, binascii, re
# converts a denary integer n into a binary string bStr
def Denary2Binary(n):
bStr = ''
if n < 0: raise ValueError, "must be a positive integer"
if n == 0: return '0'
while n > 0:
bStr = str(n % 2) + bStr
n = n >> 1
return bStr
# decodes the PDU Message to a readable message
def pduSMS(smsMessage, messageLenght, path):
pdu_fobj = open(path + "/cuttedPieces_ASCII/pdu.ascii", "a")
pdu_fobj.write(smsMessage + "\n")
# String to HEX
smsMessage = smsMessage.decode("hex")
# HEX -> BIN 8-bit
bin8sms = ""
for part in smsMessage:
ordpart = ord(part)
bin = Denary2Binary(ordpart)
bin8sms = bin8sms + bin
# split BIN string in parts with length of 8 digits
part = ""
i = 0
k = 0
while k < len(bin8sms):
k = i + 8
for j in range(i, i+8):
if k < len(bin8sms):
part = part + bin8sms[j]
else:
rest = (len(bin8sms) % 8)
for m in range(i, i + rest):
part = part + bin8sms[m]
break
part = part + ";"
i = i+8
# BIN 8-bit -> BIN 7-bit
l = part.split(";")
for i in range(len(l) - 1):
l[i+1] += l[i][:i+1]
l[i] = l[i][i+1:]
bin7sms = str(l)
# BIN 7-bit -> DEC
i = 0
decsms = ""
while i < len(l):
if i <= len(l) and l[i] != "":
decsms = decsms + str(int(l[i], 2)) + ";"
i += 1
else:
break
# DEC -> ASCII
asciisms = ""
n = decsms.split(";")
for p in range(len(n) - 2):
char = int(n[p])
if char < 256:
asciisms = asciisms + chr(char) + ";"
pdu_fobj.write("ascii: " + asciisms + "\n")
pdu_fobj.close()
Verfasst: Sonntag 17. Mai 2009, 00:54
von BlackJack
@#cousin#: Vergiss am besten die Funktion aus dem Netz. Mit der kann man nicht direkt Bytes/Zeichen in Binärdarstellung überführen.
Deine `Denary2Binary()` hat den falschen Namen und die falsche Beschreibung im Kommentar. Die wandelt *Integer* in eine Binärdarstellung als Zeichenkette um. Integer haben keine Basis, das sind einfach ganz abstrakt ganze Zahlen in irgendeiner internen Darstellung. Normalerweise zur Basis zwei, weil Rechner so gestrickt sind, aber das braucht den Programmierer nicht weiter zu interessieren.
Die Kommantare, die Du über die Funktionen setzt, machen sich übrigens ganz gut als Docstrings.
Bitoperationen benutzt Du gerade nicht, Du wandelst die Zahlen in eine Zeichenkette mit einer Darstellung zur Basis 2 um und machst dann Zeichenkettenoperationen darauf. Bitoperationen sind Bitverschiebungen, bitweises Und und Oder auf *Zahlen*, nicht auf Zeichenketten.
Womit wir beim `ord()` wären, was den Zahlwert zu einem Zeichen, also zu einem Byte liefert. Genau mit diesem Zahlwert und den Bitoperationen würde man das Problem direkt lösen können, ohne die unschönen Umwege. Meine `decode()`-Funktion nimmt Zahlen zwischen 0 und 255 und liefert einen Generator über Zahlen im 7-Bit-Bereich, also die dekodierten Daten. Diese 9 Zeilen sind alles was man braucht um von 8-Bit-Werten auf die 7-Bit-Werte zu kommen.
Verfasst: Sonntag 17. Mai 2009, 10:25
von #cousin#
Hi,
ich befürchte, dass ich dir gerade (bzw. die ganze Zeit schon) nicht so ganz folgen kann
wenn ich dich richtig verstanden habe arbeite ich am Anfang wie bisher:
- string in hex decodieren
- ord() anwenden
-danach nehme ich deine decode() von weiter oben
-und auf das Ergebnis wende ich chr() an
stimmt das so?
Verfasst: Sonntag 17. Mai 2009, 11:59
von BlackJack
Nicht ganz, die Hex-Kodierung ist immer noch ein Schritt zuviel.
Code: Alles auswählen
def decode(encoded):
carry = 0
for i, byte in enumerate(encoded):
shift = i % 7
yield ((byte << shift) | carry) & 0x7f
carry = byte >> (7 - shift)
if shift == 6:
yield carry
carry = 0
def main():
encoded = '\xe82\x9b\xfdF\x97\xd9\xec7'
decoded = ''.join(map(chr, decode(map(ord, encoded))))
assert len(decoded) == len(encoded) + len(encoded) // 7
print decoded
Verfasst: Dienstag 19. Mai 2009, 10:28
von #cousin#
Hi BlackJack,
vielen Dank für die Unterstützung bei meinem Problem, allerdings bin ich noch nicht ganz dort wo ich hin möchte.
mein Skript sieht aktuell folgendermaßen aus:
Code: Alles auswählen
#!/usr/bin/python
#
import string
# decodes the PDU Message to a readable message
def pduSMS(smsMessage, messageLenght, path):
pdu_fobj = open(path + "/cuttedPieces_ASCII/pdu.ascii", "a")
pdu_fobj.write(smsMessage + "\n")
output = ""
output2 = ""
sub = "\\x"
for char in range(0, len(smsMessage), 2):
output = sub + smsMessage[char] + smsMessage[char + 1]
output2 = output2 + output
asciisms = main(output2)
pdu_fobj.write("ascii: " + asciisms + "\n")
pdu_fobj.close()
def decode(encoded):
carry = 0
for i, byte in enumerate(encoded):
shift = i % 7
yield ((byte << shift) | carry) & 0x7f
carry = byte >> (7 - shift)
if shift == 6:
yield carry
carry = 0
def main(encoded):
decoded = ''.join(map(chr, decode(map(ord, encoded))))
assert len(decoded) == len(encoded) + len(encoded) // 7
print decoded
return decoded
die decode() und die main() sind von dir, da habe ich nur den Beispiel-String entfernt.
die pduSMS() sollte nichts anderes machen als den ursprünglichen String in eine Datei zu schreiben und danach aus:
den folgenden String mache:
damit deine main() was damit anfangen kann.
leider wird aus "E8329BFD4697D9EC37" nicht "hellohello" sondern ein String aus Steuerzeichen und nicht druckbaren Zeichen.
hast du noch eine Idee woran das liegen könnte?
Verfasst: Dienstag 19. Mai 2009, 20:46
von BlackJack
Du musst Dir mal klar werden was für Daten im Speicher stehen und wie die Dargestellt werden, wenn Du sie als literale in den Quelltext schreibst, bzw. mit `repr()` ausgibst. '\\xE8' ist etwas *völlig* anderes als '\xE8'. Das erste sind *vier* Zeichen die ausgegeben \xE8 ergeben und das zweite ist *ein* Zeichen, das ausgegeben je nach Kodierung der Konsole ein "komisches" Zeichen oder ein Kästchen oder "Fragezeichen" ergibt, und den Bytewert 0xE8 (hexadezimal) oder 232 (dezimal) hat.
Wenn Du aus der Zeichenkette 'E8329BFD4697D9EC37' neun Bytes machen willst, dann überleg doch mal wie Du vorher aus einer Zeichenkette mit binärdaten so eine Hex-Darstellung gemacht hast. Mit `encode('hex')` -- und nun rate mal wie die andere Richtung geht.
Wobei ich mich frage warum Du vorher `encode()` verwendet hast, wenn Du doch anscheinen jetzt bei gleichen Daten(?) die Gegenrichtung brauchst!?
Verfasst: Mittwoch 20. Mai 2009, 00:24
von #cousin#
Hi BlackJack,
also war mein decode(hex) aus dem obigen Beitrag doch richtig!?
Nun geht es auch fast so wie es soll, er setzt nur die Umlaute nicht richtig um, aber das bekomm ich per Regulärem-Ausdruck noch hin.
Vielen Dank für deine Unterstützung!