Alternative zu string.split(delimiter, 1) für bestimmt. Sub?

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.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

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:

Code: Alles auswählen

s = "beach;sun;water;shark;work;boss;deadlines"
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. :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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'
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

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

Code: Alles auswählen

s = "beach;sun;water;shark;work;boss;deadlines"
zur Liste:

Code: Alles auswählen

['beach;sun;water;shark', 'work;boss;deadlines']
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']
Zuletzt geändert von Seeker am Donnerstag 1. Oktober 2009, 11:07, insgesamt 1-mal geändert.
karolus
User
Beiträge: 145
Registriert: Samstag 22. August 2009, 22:34

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
Zuletzt geändert von karolus am Donnerstag 1. Oktober 2009, 11:28, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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')
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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')
;)
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`.*` 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.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

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
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

@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']
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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()
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Achso =). Da ich 'string' nie wirklich importieren musste, war mir der Unterschied eigentlich nie aufgefallen :roll:.
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Seeker: Etliche Funktionen des `string`-Moduls sind in Python 3.0 abgeschafft worden. hier eine Übersicht.

@jbs: Danke für die Erklärung.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

@ 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 =).
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Lesen geht genauso schnell :P.

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 =/.
Benutzeravatar
snafu
User
Beiträge: 6881
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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'
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Jup, das beantwortet meine Frage, danke :)
Antworten