Seite 1 von 1
Steuerzeichen aus String filtern
Verfasst: Montag 7. April 2008, 21:39
von carknue
Hallo,
ich muss aus einem String(wlist[3]) alle nichtdruckbaren Steuerzeichen rausfiltern. Es muss geschwindigkeitsoptimiert sein und ich kann nur Python 2.2 (auf Handy) nutzen. Ich habe mir folgendes überlegt, was auch funktioniert. Aber geht das noch schneller, vielleicht mit der map funktion?
Code: Alles auswählen
string = ""
for zeichen in wlist[3]:
if ord(zeichen) < 32 or (126 < ord(zeichen) < 160):
zeichen = ""
string = string + zeichen
wlist[3] = string
Gruss
Carsten
Verfasst: Montag 7. April 2008, 22:01
von EyDu
Probier mal:
Code: Alles auswählen
def is_not_control(c):
c = chr(c)
return not (c < 32 or 126 < c < 160)
filter(is_not_control, my_string)
Verfasst: Montag 7. April 2008, 23:34
von carknue
@ EyDu
ok, statt chr(c) muss es ord(c) heissen aber es funktioniert leider nicht an allen stellen im Programm. Manchmal bekomme ich dann als Ergebnis von der filter funktion nicht den String, sondern die Liste, also statt "Hallo" "[u'H',u'a',u'l',u'l',u'o']"
Verfasst: Montag 7. April 2008, 23:41
von EyDu
Man könnte natürlich daraus ein
machen. Ich bekomme jedoch immer Strings raus. Hast du vielleicht ein Beispiel, wo es bei dir nicht funktioniert.
Verfasst: Montag 7. April 2008, 23:42
von audax
Code: Alles auswählen
def is_not_control(c):
c = ord(c)
return not (c < 32 or 126 < c < 160)
u''.join(filter(is_not_control, my_string))
Dan joint man diese Liste eben wieder zusammen...
€dit:
Ich werd alt und langsam /o\
€dit²:
Code: Alles auswählen
In [14]: def is_not_control(c):
c = ord(c)
return not (c < 32 or 126 < c < 160)
....:
In [17]:
In [18]: f = functools.partial(filter, is_not_control)
In [19]: f("""dsadsadsadsdsad+#+#%&/()
\t
\t
sadsad
""")
Out[23]: 'dsadsadsadsdsad+#+#%&/()sadsad'
Läuft bei mir prächtig :]
Verfasst: Montag 7. April 2008, 23:59
von carknue
Hmm, ok. Die Frage ist dann, ob das wirklich einen Geschwindigkeitsvorteil bringt? Müsste ich dann mal testen oder kann mir das jemand plausibel erklären? Ich weiß, for Schleifen sind eher langsam... Ich habe meinen Code jetzt mal so gemacht:
Code: Alles auswählen
def is_not_control(input):
string = ""
for zeichen in input:
if ord(zeichen) < 32 or (126 < ord(zeichen) < 160):
zeichen = ""
string += zeichen
return string
Verfasst: Dienstag 8. April 2008, 00:50
von EyDu
Um das Testen wirst du wohl kaum herumkommen.
Verfasst: Dienstag 8. April 2008, 06:23
von audax
dax@grimbold ~ :) % python bench.py
17.4521019459
18.9652159214
http://paste.pocoo.org/show/38594
Ist also...marginal. Trotzdem ist die filter() Lösung hübscher :D
Verfasst: Dienstag 8. April 2008, 13:24
von EyDu
Es geht ja nicht darum, wie schnell die Lösung auf irgend einem PC ist, sondern auf einem Handy/Samartphone. Dort verhalten sich einige Operationen ja recht unterschiedlich.
Verfasst: Dienstag 8. April 2008, 16:26
von audax
Da auf dem Handy 2.2 läuft, ist vermutlich die filter-Lösung fixer, aber mehr als spekulieren kann ich da auch nicht, das muss carknue schon selbst testen.
Verfasst: Dienstag 8. April 2008, 20:13
von carknue
Erstmal Danke fürs benchen, auf dem Handy gibt es leider weder functools, noch timeit. Auf meinem PC ist die for Schleife aber einen Tick flotter.
.
IDLE 1.2.1
>>> ================================ RESTART ================================
>>>
8.05010858246
6.94058707765
Und die Schleife noch weiter abgespeckt wird der Unterschied zu gunsten der Schleife noch größer. Oder Interpretiere ich die Ergebnisse falsch?
Code: Alles auswählen
# -*- coding: utf-8 -*-
import functools
def sane_char(c):
c = ord(c)
return not (c < 32 or 126 < c < 160)
f = functools.partial(filter, sane_char)
def is_not_control(input):
string = ""
for zeichen in input:
input = ord(zeichen)
if not input < 32 or (126 < input < 160):
string += zeichen
return string
if __name__=='__main__':
from timeit import Timer
STRING = "FOOO§$fds\t\t\\n\r\nSFD"
t = Timer("f(STRING)", "from __main__ import STRING, f")
print t.timeit()
t = Timer("is_not_control(STRING)", "from __main__ import STRING, is_not_control")
print t.timeit()
>>>
8.17552013851
5.49103833806
Re: Steuerzeichen aus String filtern
Verfasst: Mittwoch 9. April 2008, 08:54
von jens
carknue hat geschrieben:ich kann nur Python 2.2 (auf Handy) nutzen.
Damit fällt die [mod]functools[/mod] Variante flach
Ich hab da noch einen:
Code: Alles auswählen
# -*- coding: utf-8 -*-
import timeit, string
loop = 100000
WHITELIST_STRING = string.ascii_letters + string.digits
def is_not_control1(input):
string = ""
for zeichen in input:
if ord(zeichen) < 32 or (126 < ord(zeichen) < 160):
zeichen = ""
string += zeichen
return string
def is_not_control2(input):
string = ""
for zeichen in input:
if ord(zeichen) < 32 or (126 < ord(zeichen) < 160):
continue
string += zeichen
return string
def is_not_control3(input):
result = []
for zeichen in input:
if zeichen in WHITELIST_STRING:
result.append(zeichen)
return "".join(result)
def is_not_control4(input):
string = ""
for zeichen in input:
if zeichen in WHITELIST_STRING:
string += zeichen
return string
if __name__=='__main__':
TEST_STRING = "FOOO§$fds\\t\\t\\n\\r\\nSFD"
tests = (
("is_not_control1('%s')" % TEST_STRING, "from __main__ import is_not_control1"),
("is_not_control2('%s')" % TEST_STRING, "from __main__ import is_not_control2"),
("is_not_control3('%s')" % TEST_STRING, "from __main__ import is_not_control3"),
("is_not_control4('%s')" % TEST_STRING, "from __main__ import is_not_control4"),
)
for no, test in enumerate(tests):
print "%s - %s" % (no+1, test[0])
test = timeit.Timer(test[0], test[1])
print "%.2f" % test.timeit(number=loop)
print
Ergebnis:
1 - is_not_control1('FOOO§$fds\t\t\n\r\nSFD')
0.85
2 - is_not_control2('FOOO§$fds\t\t\n\r\nSFD')
0.77
3 - is_not_control3('FOOO§$fds\t\t\n\r\nSFD')
0.68
4 - is_not_control4('FOOO§$fds\t\t\n\r\nSFD')
0.45
Verfasst: Mittwoch 9. April 2008, 11:33
von BlackJack
`functools.partial()` kann man ja durch eine ``lambda``-Funktion ersetzen.
Ansonsten würden mir noch Variationen für die ersten beiden Funktionen einfallen: Das `ord()` weglassen und dafür die Zahlen als Zeichen(ketten) schreiben. Also statt ``ord(zeichen) < 32`` zum Beispiel ``zeichen < ' '``. So spart man die `ord()`-Aufrufe.
Verfasst: Mittwoch 9. April 2008, 14:14
von helduel
Moin,
ich erweitere mal jens' Beispiele:
Code: Alles auswählen
def is_not_control5(input):
return filter(string.printable.__contains__, input)
Ergebnis auf meiner Maschine:
1 - is_not_control1('FOOO§$fds\t\t\n\r\nSFD')
1.03
2 - is_not_control2('FOOO§$fds\t\t\n\r\nSFD')
0.94
3 - is_not_control3('FOOO§$fds\t\t\n\r\nSFD')
0.93
4 - is_not_control4('FOOO§$fds\t\t\n\r\nSFD')
0.69
5 - is_not_control5('FOOO§$fds\t\t\n\r\nSFD')
0.44
Gruß,
Manuel