Wörter separieren

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.
Antworten
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Guten Abend,

meine Frage ist: Hat jemand eine Idee, wie ich am besten die einzelnen Wörter eines Satzes auflisten kann?
Also wenn ich z.B. text = "Hallo liebe Leute!" habe, wie könnte man das machen, dass man dann ['Hallo', 'liebe', 'Leute', '!'] herausbekommt?

Ich hab an sowas gedacht, dass man sicher mal die char-Werte der Funktion übergeben soll. Dann habe ich mir überlegt, ob es nicht eine Funktion gibt, die überprüft, wie gross ein Wort ist bzw. eine Funktion die schaut, bis wann ein Leerzeichen folgt. Wenn man sowas hätte, könnte man die einzelnen Wörter schön abgrenzen und dann wie gewünscht ausgeben.

Code: Alles auswählen

def func(self, char):
     
Ich danke vielmals für die Hilfe!
BlackJack

@MarcelF6: Schau Dir mal reguläre Ausdrücke im Allgemeinen und das `re`-Modul im besonderen an.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Für dieses Problem gibt es regular expressions.

Code: Alles auswählen

>>> import re
>>> text = "Hallo liebe Leute!"
>>> re.findall(r"\w+|\S+", text)
['Hallo', 'liebe', 'Leute', '!']
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Ha cool! :) Ich wusste doch, dass es sowas gibt.
Vielen Dank! :)
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Ich habe noch eine Frage bezüglich Klassen: Wenn eine Klasse von einer anderen erbt, schreibt man ja:

Code: Alles auswählen

class Child(Father):
Nun habe ich noch gelesen, man solle

Code: Alles auswählen

if __name__ == "__main__":
dem Code hinzufügen, um es als Skript zu definieren.
(dumme) Frage: Ist __name__ und __main__ mit etwas zu ersetzen?
Ganz allgemein: Wenn man die Klasse als Skript definiert, was ändert sich dabei konkret? So wie ich das verstanden habe muss man am Code sonst nichts verändern, man kann in einfach per python name.py aufrufen. Ist das richtig?
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

MarcelF6 hat geschrieben:(dumme) Frage: Ist __name__ und __main__ mit etwas zu ersetzen?
Nein, das steht so fest.
MarcelF6 hat geschrieben:Ganz allgemein: Wenn man die Klasse als Skript definiert, was ändert sich dabei konkret?
Wie soll man denn eine Klasse als Skript definieren? Diese `if'-Abfrage ist dazu da, Code nur auszuführen, wenn das Programm ausgeführt wird, und nicht durch ein anderes Skript importiert. Zum Beispiel kannst du das `doctest'-Modul per `import doctest' importieren, aber auch als Skript ausführen: Da muss ein Dateiname als Argument übergeben werden und dann werden die Docstrings nach Tests durchsucht und ausgeführt.
BlackJack

@MarcelF6: Du verwechselst anscheinend Klasse und Modul. Die ``if``-Abfrage macht aus einem Modul auch kein Skript — das kann es auch ohne diese Abfrage sein — sondern sorgt dafür, dass man ein Skript auch als Modul importieren kann und dabei eben mit dieser Abfrage verhindern kann, dass dann der Code für das Skript ausgeführt wird. So kann man ein Modul als Skript und als importierbares Modul verwenden um zum Beispiel Testcode mit dem Inhalt laufen zu lassen oder den Inhalt in anderen Modulen oder Skripten wieder zu verwenden.

Der Name `__name__` ist immer an den Namen des Moduls gebunden, ausser wenn das Modul nicht importiert, sondern direkt als Skript ausgeführt wird — dann ist der Name an '__main__' gebunden. So kann man unterscheiden ob der Code auf Modulebene ausgeführt wird, weil das Modul von einem anderen Modul importiert wurde, oder als Programm laufen soll.

Falls Du Datei, und damit Modul, und Klasse bisher gleich gesetzt hast: In Python ist es nicht üblich für jede Klasse eine eigene Datei zu schreiben, wie zum Beispiel in Java.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Du kannst das bei Bedarf natürlich etwas sprechender gestalten:

Code: Alles auswählen

is_imported = (__name__ != '__main__')

if is_imported:
    print 'Have been imported as a module'
else:
    print 'Have been called as a script'
...und danach die Datei einmal aus der Shell heraus mittels `python programmname.py` und anschließend als Modulimport aufrufen. Dann sollte der Unterschied ziemlich deutlich werden.

Wie gesagt, das Ganze dient nicht als eine Art Markierung, sondern eher als Abfrage, ob die "Markierung" (nämlich: `__name__ == '__main__'`) gesetzt wurde, um anschließend spezifischen Code je nach Ausführungart laufen zu lassen.

Ein konkretes Beispiel wäre in deinem Fall eine Funktion, welche halt aus einem String die Wörter und Satzzeichen trennt. Im "Als-Skript-Zweig" möchtest du vielleicht abfragen, ob der Benutzer Kommandozeilenargumente mitgegeben hat (z.B. eine Zeichenkette, die den Text zum Trennen liefert) und deine Trennfunktion damit aufrufen, während bei einem direkten Import erstmal nichts passieren soll (da das Prüfen der Kommandozeilenargumente dann natürlich Unsinn ist). Die Funktion selbst ist aber in beiden Fällen definiert.

Ich hoffe, der Zweck von dieser Unterscheidung ist damit einigermaßen klar geworden. :)
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Vielen Dank für die Tipps und die Hilfe.

Eine spezifische Frage zur Vererbung habe ich noch:
Wenn ich z.B. eine Klasse Father() habe:

Code: Alles auswählen

class Father():
    def __init__(self):
        self.zeichen = set(".,;:!?()\"")
    
    def tok(self, text):
        fertig = ""
        for char in text:
            fertig += self._auseinander(char)
            
        return fertig.split()

    def _auseinander(self, char):
        if char in self.zeichen:
            char = " " + char
    
        return char

test = Child()
print test.tok("Hallo liebe Leute!")
und eine Kind-Klasse machen möchte, die genau obiges Verhalten hat, so habe ich folgendes gemacht:

Code: Alles auswählen

import re

class Child(Father):

    is_imported =  (__name__ != "__main__")

    if is_imported:
        print("Wurde als Modul importiert.")
    else:
        print("Wurde als Skript aufgerufen.")

    def _auseinander(self, char):
        super._auseinander(self, char)
        re.findall(r"\w+|\S+", char)
Nun gibt mir die shell aber eine Fehlermeldung aus, dass name 'Child' nicht definiert ist.
Daher habe ich die Vermutung, dass evtl. mehrere Sachen noch nicht korrekt sind. Dass die Vererbungssyntax korrekt ist, bin ich ziemlich sicher. Aber wie gesagt, irgendwo gibt es sicher noch Fehler, allerdings weiss ich nicht wo.
Danke vielmals für die Hilfe.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bitte poste lauffähigen Quellcode, auch wenn er von der eigentlichen Aufgabenstellung abstrahiert wurde. Meistens kommt man sogar schon in dem Moment, wo man ein Problem abstrakt beschreiben bzw in Quellcode umsetzen muss, selbst auf die Lösung. Deine Snippets würden beide Fehler werfen - das sieht man schon beim bloßen Draufgucken.

Was ich übrigens noch nicht so ganz verstehe: Was hat das alles eigentlich mit einer "skriptartigen" Ausführung zu tun? Offenbar willst du doch einfach nur eine Trennung sowohl an Stellen, wo Whitespace ist, als auch beim Wechsel zwischen Buchstaben- und Satzzeichen. Der vorherige Code muss also so erweitert werden, dass er auch mit dem besagten Wechsel klarkommt.

Hast dir eigentlich schon das von BlackJack vorgeschlagene `re`-Modul näher angeguckt (Doku)? Dort gibt es `re.split()`, was ja ganz eventuell (*hüstel*) ein guter Kandidat für die Aufgabe wäre...

//edit: Huch, jetzt verstehe ich den Code erstmal. Das ist ja quasi schon eine Art `re.split()` mit entsprechendem regulären Ausdruck - nur halt etwas komplizierter bzw ohne `re`-Modul. :oops:
BlackJack

@MarcelF6: Fehlermeldungen bitte am besten komplett 1:1 hier rein kopieren und den gesamten Quelltext zeigen.

Hast Du die beiden Quelltextfragmente in verschiedenen Dateien? Und die ``import``-Anweisungen hier nicht einfach nur weg gelassen, sondern auch tatsächlich keine im Quelltext? Im ersten Quelltextfragment wird `Child` ja nirgens definiert, also bekommt man da eine Ausnahme.

Falls beide Fragmente in verschiedenen Dateien stehen sollten, dann müssten die sich gegenseitig importieren, was zu Problemen führt wenn man nicht ganz genau weiss was man da macht und in welcher Reihenfolge dann der Code auf Modulebene ausgeführt wird. In der Regel sind zwei Module die sich gegenseitig benötigen ein Zeichen dafür, dass man entweder nur ein Modul mit dem Inhalt von beiden haben möchte, oder dass man gemeinsame Abhängigkeiten in ein weiteres Modul auslagern sollte.

In `tok()` erst eine Zeichenkette zusammensetzen, um die gleich danach mit `split()` wieder zu teilen, sieht ein wenig umständlich aus. Man sollte auch nicht Zeichenketten durch wiederholtes ``+`` oder ``+=`` zusammen setzen, denn da werden im schlechtesten Fall immer wieder neue Zeichenketten erstellt und die Daten unnötig im Speicher herum kopiert. Idiomatischer wäre es die Teilzeichenketten beispielsweise in einer Liste zu sammeln und dann die `join()`-Methode auf Zeichenketten zu verwenden, um am Ende eine Zeichenkette aus den Teilen zu erstellen.

Im `Child` verstehe ich nicht so ganz was `is_imported` und die Abfrage danach auf Klassenebene zu suchen haben!?

In `_auseinander()` wirst Du einen `AttributeError` bekommen, weil die `super()`-Funktion anders verwendet wird. Ich persönlich würde von `super()` die Finger lassen, denn man braucht es nur bei Mehrfachvererbung und man holt sich ziemlich viel Komplexität ins Boot verglichen mit einem einfachen ``Father._auseinander(self, char)``. Siehe auch http://fuhm.net/super-harmful/
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Vielen Dank euch allen.
Hab mittlerweilen alles zusammen gekriegt :)

Eine technisch/theoretische Frage habe ich noch: Wenn ich eine Mutter und eine Kindklasse (also vererbt) habe, und einmal den Code per import-Statement (also als Modul) importiere und einmal als Skript aufrufe - wieso kann es dann verschiedene Ausgaben geben?

Ist meine Vermutung korrekt dass wenn ich den Code als Skript aufrufe, dass dann nur der Code der Mutterklasse abgerufen wird? Und beim import-Statement wird alles ausgegeben.
Oder wo liegen die Unterschiede?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Egal ob du eine Datei direkt ausführst oder diese als Modul importierst, diese werden im Prinzip gleich behandelt. Wichtig ist beim Importieren eines Moduls, dass der Code, welcher sich auf Modulebene befindet, nur einmal ausgeführt wird. Auf Vererbung hat der Unterschied Modul/Script gar keine Auswirkung, dass wäre auch sehr wirr.

Die Unterschiede ergeben sich durch das bereits genannte ``if __name__ == "__main__"``-Konstrukt. Damit wird sichergestellt, dass der Code nur beim Starten als Script ausgeführt wird und nicht beim Importieren. Falls du das Problem in deinem Code nicht findest, konstruiere am besten ein minimales lauffähges Beispiel und erkläre, was du erwartest und was tatsächlich passiert.
Das Leben ist wie ein Tennisball.
Antworten