Seite 1 von 2
Alternative zu string.split(delimiter, 1) für bestimmt. Sub?
Verfasst: Donnerstag 1. Oktober 2009, 10:20
von Seeker
Hi!
Ich bin gerade dabei, "Dive into Python" durchzuarbeiten.
Ich habe zu folgender Aussage eine Frage:
anystring.split(delimiter, 1) is a useful technique when you want to search a string for a substring and
then work with everything before the substring (which ends up in the first element of the returned list) and
everything after it (which ends up in the second element).
Ich habe folgenden String:
und möchte eine Liste, die aus den Elemtenten 'beach;sun;water;shark' und 'work;boss;deadlines' besteht.
Code: Alles auswählen
>>> s = "beach;sun;water;shark;work;boss;deadlines"
>>> s.split(";",1)
['beach', 'sun;water;shark;work;boss;deadlines']
>>> s.split("ark;", 1) #Wenn ich sage, ich möchte nach "Shark" abtrennen, löscht
#leider ja den ganzen Delimiter mit.
['beach;sun;water;sh', 'work;boss;deadlines']
## Dieser Weg funktioniert zwar... scheint mir aber sehr aufwendig, dazu muss
## ich schon zu Beginn wissen, an welcher Stellt sich "shark" befindet.
## Das suchen könnte ich auch mit s.split(";") und dann s.index("shark") machen,
## aber das ist auch wieder so unschön.
>>> s = s.split(";", 4)
>>> t = s.pop()
>>> s
['beach', 'sun', 'water', 'shark']
>>> s = [";".join(s)]
>>> s.append(t)
>>> s
['beach;sun;water;shark', 'work;boss;deadlines']
Gibt es einen direkten Weg, die Liste nach "Shark" zu splitten und nur das ";" nach Shark zu löschen?
Ich habe keine genaue Anwendung im Kopf, es geht mir nur um das Verständnis des Prozesses.

Verfasst: Donnerstag 1. Oktober 2009, 10:46
von Hyperion
Wenn Du nicht weißt, an welcher Stelle "Shark" vorkommt, dann macht es doch auch keinen Sinn die enstehende Liste zu beschneiden! Diese musst Du doch dann eh durchsuchen...
Das kannst Du aber ja direkt erledigen:
Code: Alles auswählen
In [1]: s = u"beach;sun;water;shark;work;boss;deadlines"
In [2]: s.split(";").index("shark")
Out[2]: 3
Allerdings sollte man dann doch einen IndexError abfangen:
Code: Alles auswählen
In [3]: s.split(";").index("foo")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
C:\Programme\Python26\Scripts\<ipython console> in <module>()
ValueError: list.index(x): x not in list
Verfasst: Donnerstag 1. Oktober 2009, 10:59
von snafu
Und anschließend könnte man die Liste mittels Slicing in zwei Hälften teilen (die Position kennt man ja jetzt) und sie jeweils mit `';'.join()` zusammensetzen. Die resultierenden Strings daraus fügt man schließlich zu einem String zusammen.
Verfasst: Donnerstag 1. Oktober 2009, 11:05
von snafu
Falls das Ziel lediglich das Entfernen und nicht die Übung ist, geht es natürlich viel einfacher:
Code: Alles auswählen
In [37]: s.replace('shark;', 'shark')
Out[37]: 'beach;sun;water;sharkwork;boss;deadlines'
Verfasst: Donnerstag 1. Oktober 2009, 11:05
von Seeker
Wenn Du nicht weißt, an welcher Stelle "Shark" vorkommt, dann macht es doch auch keinen Sinn die enstehende Liste zu beschneiden! Diese musst Du doch dann eh durchsuchen...
Das kannst Du aber ja direkt erledigen:
Ja... diese Methode habe ich ja in der Bemerkung im Code drin 'versteckt'.
Und das ValueError ist klar... ich würde dann ja den Index eines Elements verlangen, das nicht vorkommt.
Meine eigentliche Frage was jedoch im Grunde genommen, ob es einen einfacheren Weg gibt, vom String
zur Liste:
zu gelangen.
Weiter unten im Script wird ja noch erwähnt, dass die string.methods eher vermieden werden. Deshalb, gibt es eine andere Variante ohne s.split, s.join., s.pop etc. als Kombination einsetzen zu müssen, um vom obrigen String zur gesuchten Liste zu kommen?
So etwas in der Art (Phantasiecode):
Code: Alles auswählen
s = "beach;sun;water;shark;work;boss;deadlines"
s = s.split(after "shark;") #Trennt String nach "shark;" und wird zur Liste
s = ['beach;sun;water;shark;','work;boss;deadlines']
s = s.replace("shark;", "shark")
s = ['beach;sun;water;shark','work;boss;deadlines']
Verfasst: Donnerstag 1. Oktober 2009, 11:05
von karolus
Hallo
Code: Alles auswählen
if "shark" in s:
[s[:s.index("shark")+5 ],s[s.index("shark")+6 :]]
...
['beach;sun;water;shark', 'work;boss;deadlines']
Gruß Karo
Verfasst: Donnerstag 1. Oktober 2009, 11:10
von Hyperion
Naja, das ginge per RegExp:
Code: Alles auswählen
In [17]: s = u"beach;sun;water;shark;work;boss;deadlines"
In [18]: m = re.search(r"shark;", s)
In [19]: s[:m.end()], s[m.end():]
Out[19]: (u'beach;sun;water;shark;', u'work;boss;deadlines')
Verfasst: Donnerstag 1. Oktober 2009, 11:10
von snafu
Seeker hat geschrieben:Weiter unten im Script wird ja noch erwähnt, dass die string.methods eher vermieden werden.
Die Funktionen aus dem `string`-Modul sollten deshalb vermieden werden, weil sie jetzt direkt als Methoden des String-Objekts aufgerufen werden können, also kein Import des Moduls mehr nötig ist. Das heißt aber nicht, dass sie an sich schlecht sind.
Und wenn man's ganz genau haben will:
Code: Alles auswählen
In [46]: s[:re.search('shark', s).end()], s[re.search('work', s).start():]
Out[46]: ('beach;sun;water;shark', 'work;boss;deadlines')

Verfasst: Donnerstag 1. Oktober 2009, 11:33
von HWK
Wenn man schon eine Regex verwendet, dann
Code: Alles auswählen
>>> s = 'beach;sun;water;shark;work;boss;deadlines'
>>> result = re.match('(.*?shark);(.*)', s)
>>> result.groups()
('beach;sun;water;shark', 'work;boss;deadlines')
MfG
HWK
Verfasst: Donnerstag 1. Oktober 2009, 12:15
von snafu
`.*` heißt "beliebige Zeichen", oder? Und warum muss man für den Teil danach ein Fragezeichen dazupacken? Zumindest bei diesem String wird's auch ohne Fragezeichen gefunden. Ich hab aber auch kaum Ahnung von regulären Ausdrücken.
Verfasst: Donnerstag 1. Oktober 2009, 12:26
von Seeker
Sry, war mal kurz essen

. Danke für die zahlreichen Antworten!
Am einfachsten ist wahrscheinlich karolus' Code. Mit Regex hatte ich noch keine Begegnung, aber der Code sieht toll aus

.
Die "Schnellversion" (d.h. für einen Anfänger wie mich nicht übersichtlich, aber direkt und 'fastforward') wäre also:
Code: Alles auswählen
>>> s = 'beach;sun;water;shark;work;boss;deadlines'
>>> s = re.match('(.*?shark);(.*)', s).groups()
>>> s
('beach;sun;water;shark', 'work;boss;deadlines')
Die Funktionen aus dem `string`-Modul sollten deshalb vermieden werden, weil sie jetzt direkt als Methoden des String-Objekts aufgerufen werden können, also kein Import des Moduls mehr nötig ist. Das heißt aber nicht, dass sie an sich schlecht sind.
ok... ich sehe das Problem dabei nicht ganz, aber das wird wahrscheinlich noch in der Doku bemerkt

. Oder ist es einfach grundsätzlich von Vorteil, built-in functions zu vermeiden?
lg Seeker
Verfasst: Donnerstag 1. Oktober 2009, 12:30
von jbs
@snafu
Code: Alles auswählen
In [13]: s = "<html> <body><h1>bla</h1> <h1>blub</h1> </body> </html>"
In [14]: re.findall("<h1>(.*)</h1>",s)
Out[14]: ['bla</h1> <h1>blub']
In [15]: re.findall("<h1>(.*?)</h1>",s)
Out[15]: ['bla', 'blub']
Verfasst: Donnerstag 1. Oktober 2009, 12:30
von Hyperion
Seeker hat geschrieben:
Am einfachsten ist wahrscheinlich karolus' Code. Mit Regex hatte ich noch keine Begegnung, aber der Code sieht toll aus

.
Um das ganze dabei aber genereisch zu halten, müßte man vorher noch die Länge des Suchbegriffs ermitteln.
ok... ich sehe das Problem dabei nicht ganz, aber das wird wahrscheinlich noch in der Doku bemerkt

. Oder ist es einfach grundsätzlich von Vorteil, built-in functions zu vermeiden?
Nein, built-in functions sind idR. das zu empfehlende Mittel. Hier geht es um folgendes:
Code: Alles auswählen
# eher unschön
import string
string.some_method("foo bar")
# besser
"foo bar".some_string_method()
Verfasst: Donnerstag 1. Oktober 2009, 12:37
von Seeker
Achso =). Da ich 'string' nie wirklich importieren musste, war mir der Unterschied eigentlich nie aufgefallen

.
Verfasst: Donnerstag 1. Oktober 2009, 12:38
von snafu
@Seeker: Etliche Funktionen des `string`-Moduls sind in Python 3.0 abgeschafft worden.
hier eine Übersicht.
@jbs: Danke für die Erklärung.
Verfasst: Donnerstag 1. Oktober 2009, 12:46
von Seeker
@ snafu:
wow.. das ist eine ziemliche Liste ^^.
Aber ist nur die (auf Hyperions Code zurückgreifend) string.some_method("foo bar") abgeschafft, oder auch "foo bar".some_string_method()?
Sollte man sich einfach daran gewöhnen, die zweite Schreibweise zu nutzen?
Momentan nutze ich noch Python 2.6, aber bringt ja nicht viel wenn man sich in eine Sprache 'einübt', die dann später nicht mehr gebraucht werden kann =).
Verfasst: Donnerstag 1. Oktober 2009, 12:49
von snafu
In der langen Liste steht, was abgeschafft wird. Benutz doch einfach die Suchfunktion deines Browsers auf der Seite und gib den Funktionsnamen ein, der dich interessiert.
Im Übrigens denke ich, dass der Zweier-Zweig von Python noch eine Weile weiterentwickelt wird. Mindestens ein Release von Python 2.7 ist geplant. Und da der Umsteig auf Python 3 ja doch eher schleppend verläuft, könnte ich mir persönlich sogar ein Python 2.8 vorstellen, aber das ist Vermutung.
Verfasst: Donnerstag 1. Oktober 2009, 12:53
von Seeker
Lesen geht genauso schnell

.
Aber heisst 'rausgenommen', dass sie gar nicht mehr aufgerufen werden können, oder dass man von nun an das Modul 'string' wenn benötigt manuell importieren muss?
Sry, ist vielleicht ne dumme Frage, aber ich finds noch nicht ganz so klar =/.
Verfasst: Donnerstag 1. Oktober 2009, 13:03
von snafu
Vielleicht verstehst du's so besser:
Code: Alles auswählen
In [1]: s = 'spam'
In [2]: type(s)
Out[2]: <type 'str'>
`s` ist also ein Objekt vom Typ `str`, dass der Python-Interpreter automatisch erstellt, wenn er sieht, dass er etwas in Anführungszeichen einem Namen zuordnen soll. Anders gesagt: Es ist quasi eine Klasse, die String heißt. Und diese Klasse hat etliche Funktionen, die es im `string`-Modul gibt, zusätzlich (und in der Zukunft ausscchließlich) als eigene Methoden erhalten. Das heißt, es muss eben *nicht* mehr das Modul importiert werden, um an die Funktionalität zu kommen, sondern man kann sie direkt über die Klasse aufrufen:
Code: Alles auswählen
In [3]: import string
In [4]: string.upper('foo')
Out[4]: 'FOO'
In [5]: 'foo'.upper()
Out[5]: 'FOO'
Verfasst: Donnerstag 1. Oktober 2009, 13:07
von Seeker
Jup, das beantwortet meine Frage, danke
