Namensliste in Textpassage Suche

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.
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Hallo, ich möchte gerne Wörter in einem Text suchen und mir die Position ausgeben lassen.

Das habe ich schon soweit

Code: Alles auswählen

suchname_1 = "Hänsel"
suchname_2 = "Gretel"
suchname_3 = "Hexe"

txt_suchpassage = "Hänsel und Gretel gingen durch den Wald"
if suchname_1 or suchname_2 or suchname_3 in txt_suchpassage:
    print("Found")
    print(txt_suchpassage.find(suchname_1))
    print(txt_suchpassage.find(suchname_2))
    print(txt_suchpassage.find(suchname_3))
else:
    print("not Found")


Ich möchte das ganze aber mit einer Liste machen. Beim Umgang mit listen habe ich noch irgendwo einen Denkfehler. Der Code unten gibt 3x not Found und ich verstehe nicht warum. Ich vermute (soweit ich Pyhton bisher verstehe) dass ich mit str(suchnamen) anweise dass die Reihe: "Hänsel", "Gretel", "Hexe" als ganzes gesucht werden soll. Dann wäre die Frage wie ich das einzeln mache....

Code: Alles auswählen

suchnamen = ["Hänsel", "Gretel", "Hexe"]

txt_suchpassage = "Hänsel und Gretel gingen durch den Wald."
for i in suchnamen:
if str(suchnamen) in txt_suchpassage:
    print("Found")
    print(txt_suchpassage.find(suchnamen))

else:
    print("not Found")

Für eine kurze Hilfe wo der Fehler im Code liegt wäre ich sehr dankbar.
Benutzeravatar
__blackjack__
User
Beiträge: 13071
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Namlus: Das erste ist aber auch falsch, denn ``or`` funktioniert so nicht, das geht immer in den ``if``-Zweig und nie in den ``else``-Zweig, auch wenn keiner der Namen im Text vorkommt. ``or`` ist ein binärer Operator mit einem Operator auf jeder Seite und kein umgangssprachliches „oder“.

Edit: Und beim zweiten gibt es einen Syntaxfehler; das läuft überhaupt nicht. Es ist auch nicht ganz klar wo das ``else`` am Ende hingehören soll, zu dem ``if`` oder zu dem ``for``. `i` wird nicht verwendet, ist auch ein schlechter Name für einen Namen. Und die ``if``-Bedingung kann relativ offensichtlich niemals wahr sein, bei den gezeigten Werten.
Zuletzt geändert von __blackjack__ am Montag 23. Januar 2023, 15:03, insgesamt 1-mal geändert.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

`i` ist ein bescheuerter Name für einen Suchnamen. Variablennamen sind wichtig, damit man den Code verstehen kann. Dann ist die Einrückung kaputt. Die ist in Python ebenso wichtig.
Warum benutzt Du eine for-Schleife, wenn Du die Schleifenvariable gar nicht benutzt? Hast Du Dir schonmal ausgeben lassen, was `str(suchnamen)` ergibt und ob das dann überhaupt in Deinem Text vorkommen kann?
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

__blackjack__ hat geschrieben: Montag 23. Januar 2023, 15:00 Syntaxfehler; das läuft überhaupt nicht.
Syntaxfehler heist, ich habe die Einrückung vergessen oder? Das stimmt, die habe ich bei STRG+C falsch übernommen, das fällt mir gerade auf.

Oder ist damit etwas anderes gemeint?
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Sirius3 hat geschrieben: Montag 23. Januar 2023, 15:02 `i` ist ein bescheuerter Name für einen Suchnamen.
Vielen Dank. In sämtlichen Tutorats die verwenden immer i an der stelle. z.B. for i in range usw. - ich dachte das muss immer so sein.
Sirius3 hat geschrieben: Montag 23. Januar 2023, 15:02 Dann ist die Einrückung kaputt. Die ist in Python ebenso wichtig.
Ja das habe ich beim StrG+C aus Pycharm heraus falsch übertragen.

Sirius3 hat geschrieben: Montag 23. Januar 2023, 15:02 Warum benutzt Du eine for-Schleife, wenn Du die Schleifenvariable gar nicht benutzt?
Weil ich 3 Suchbegriffe abfrage und nicht weis wie man das sonst macht[/quote]
Sirius3 hat geschrieben: Montag 23. Januar 2023, 15:02
Hast Du Dir schonmal ausgeben lassen, was `str(suchnamen)` ergibt und ob das dann überhaupt in Deinem Text vorkommen kann?
Ne, aber stimmt eine gute Idee. Daran habe ich tatsächlich nicht gedacht. Werd ich gleich machen.
EDIT: Es kommt tatsächlich ['Hänsel', 'Gretel', 'Hexe'] (Mist ich habs vermutet).
Jedoch ohne "str" (if suchnamen in txt_suchpassage:) erhalte ich den Fehler: TypeError: 'in <string>' requires string as left operand, not list
Deshalb dachte ich, da muss ein "str" hin..... und int kann es ja nicht sein..... und an der Stelle bin ich mit meinem Latein am Ende :-)
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass Du eine for-Schleife verwenden mußt, ist klar, weil Du drei Suchbegriffe abfragen willst, aber die Frage war ja, warum Du die Schleifen-Variable nicht benutzt? Sollte ein Hinweis sein, dass Du die irgendwie verwenden mußt.

Das ist das gleiche Muster, wie gib alle durch drei teilbaren Zahlen bis 30 aus:

Code: Alles auswählen

for number in range(1, 31):
    if number % 3 == 0:
        print(number)
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Sirius3 hat geschrieben: Montag 23. Januar 2023, 20:01 Sollte ein Hinweis sein, dass Du die irgendwie verwenden mußt.
Vielen Dank. Ok. Den Hinweis habe ich nicht verstanden.....

So sollte es dann richtig sein, oder? Es funktioniert... jedenfalls

Code: Alles auswählen

suchnamen = ["Hänsel", "Gretel", "Hexe"]

txt_suchpassage = "Hänsel und Gretel gingen durch den Wald."
print(list(suchnamen))

for suchname in suchnamen:
    if suchname in txt_suchpassage:
        print("Found")
        print(txt_suchpassage.find(suchname))

    else:
        print("not Found")
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Vielen Dank. In sämtlichen Tutorats die verwenden immer i an der stelle. z.B. for i in range usw. - ich dachte das muss immer so sein.
Ja, aber wird dann gemeinhin als Index bzw. Zählvariable angenommen - was bei `for i in range(0,10)` ja der Fall ist, weil da von 0 bis 9 hochgezählt wird. `for suchname in suchnamen` ist schon wesentlich besser.

Dir ist klar, das die find-Methode von Strings nur das 1. Vorkommen eines Strings in einem String findet? Wenn dein Satz lauten würde: "Hänsel und Gretel gingen durch den Wald, da liefe Hänsel gegen die Wand des Hexenhauses." und du beide Vorkommen von Hänsel finden willst, dann musst du das noch ein bisschen erweitern.

Gruß, noisefloor
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

noisefloor hat geschrieben: Montag 23. Januar 2023, 20:23
Dir ist klar, das die find-Methode von Strings nur das 1. Vorkommen eines Strings in einem String findet?

Ach so. Nein war mir nicht klar. D.h. ich brauch dann eine For Schleife in der For Schleife oder?
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Es gibt auch eine "while" Schleife, die benutzt keine Zählvariable, und könnte dann sinnvoller sein.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Kebap hat geschrieben: Dienstag 24. Januar 2023, 09:12 Es gibt auch eine "while" Schleife, die benutzt keine Zählvariable, und könnte dann sinnvoller sein.
Vielen Dank. Ok habe ich mir angesehen und im Prinzip verstanden, jedoch den Brückenschlag zu meinem Beispiel bringe ich gerade nicht zusammen. Mit Range und +1 verstehe ich . Aber wie gebe ich da an dass er suchen soll -> hier geht ja kein +1 oder eine IF-Anweisung wenn 0
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die `find` Methode von Strings kennt ein optionales Parameter, mit dem die Startposition der Suche festgelegt werden kann. Du musst also was im folgenden händisch macht wird:

Code: Alles auswählen

>>> text = 'Gretel und Gretel gingen durch den Wald.'
>>> treffer = text.find('Gretel')
>>> treffer
0
>>> treffer = text.find('Gretel', treffer+len('Gretel'))
>>> treffer
11
>>> treffer = text.find('Gretel', treffer+len('Gretel'))
>>> treffer
-1
>>>
elegant in einen Schleife packen.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13071
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und die Schleife vielleicht in eine Funktion. Und den ``in``-Test kann man sich auch sparen, denn erst zu suchen ob es drin ist, um dann noch mal zu suchen *wo* es ist, ist ja irgendwie doppelt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Holla die Waldfee.... und jetzt beisst es komplett aus, jetzt habe ich etwas gebraucht bis ich verstehe was diese Zeile genau macht.

noisefloor hat geschrieben: Dienstag 24. Januar 2023, 17:31
>>> treffer = text.find('Gretel', treffer+len('Gretel'))
>>> treffer
11

Also gebe ich doch gerade an: Suche Gretel -> dann kommt das Komma -> mit len zähle ich die Zeichen von Greta + Zeichen der vorherigen suche-> Gibt mir die neue Startposition aufgrund des oberen Suchergebnisses an.

Ich habe dem Code um ein paar Zahlen ergänzt zur Verdeutlichung um zu erklären wo ich meine Denkprobleme habe.
noisefloor hat geschrieben: Dienstag 24. Januar 2023, 17:31 >>> treffer1 = text.find('Gretel')
>>> treffer1
0
>>> treffer2 = text.find('Gretel', treffer1+len('Gretel'))
>>> treffer2
Also ich habe ja zuerst den "treffer1" auf dessen Basis berechne ich den "neuen" Startpunkt.

Wenn ich das in eine While schleife packe habe ich 2 große Fragezeigen in meinem Kopf.
1. Wenn ich den Text in eine Schleife packe "treffer = text.find('Gretel', treffer+len('Gretel'))" dann wird er mir immer das 2 vorkommen ausgeben d.h. ich müsste ja "treffer = text.find('Gretel')" außerhalb der Schleife zum ersten mal laufen lassen, oder? Wahrscheinlich nicht, aber da habe ich meine Denkprobleme wie das funktionieren soll.....
2. Wie mache ich das mit der Liste.


P.S. vielen Dank dass ihr mich so "heranführt", das hilft mir sehr viel

Code: Alles auswählen

suchnamen = ["Hänsel", "Gretel", "Hexe"]
txt_suchpassage = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe"

treffer =txt_suchpassage.find(suchnamen[0])
print (f"Außerhalb der Schleife: {suchnamen[0]} an Position {treffer}")


while treffer > -1:
    treffer = txt_suchpassage.find(suchnamen[0], treffer + len(suchnamen[0]))
    print (f"Innerhalb der Schleife: {suchnamen[0]} an Position {treffer}")




Benutzeravatar
__blackjack__
User
Beiträge: 13071
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Namlus: Das ist eigentlich eine nachprüfende Schleife für die Python keine Syntax hat, weshalb man das als ”Endlosschleife” (``while True:``) löst, die verlassen wird, wenn die entsprechende Bedingung in der Schleife nicht mehr erfüllt wird. Man vermeidet beim Programmieren Unregelmässigkeiten wie `find()` vorher mit anderen Argumenten aufzurufen. Das ist immer `find()` mit einem Startwert. Am Anfang ist der halt 0, wenn man noch keinen vorherigen Treffer hat, und abgebrochen wird die Schleife wenn es keinen Treffer gab.

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."

    name = "Hänsel"
    index = 0
    while True:
        try:
            index = text.index(name, index)
        except ValueError:
            break

        print(name, "an Position", index)
        index += len(name)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

__blackjack__ hat geschrieben: Mittwoch 25. Januar 2023, 14:51
def main():
text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."

name = "Hänsel"
index = 0
while True:
try:
index = text.index(name, index)
except ValueError:
break

print(name, "an Position", index)
index += len(name)


if __name__ == "__main__":
main()[/code]
Hey Blackjack vielen Dank für deine Hilfe.

Jetzt stehen grad lauter Fragezeichen über mir, ich muss mir das Stück für Stück zerlegen - damit ich das verstehe. z.B. sehe ich du nimmst .index
Und eine Frage: Ich sehe es immer wieder: Was macht das if am Ende? Ich verstehe den Sinn dahinter nicht. Was ist "__name__ "?

Mein Hauptproblem ist die herangehensweise bzw. "das denken":
z.B. ich will einen Wert in einem Text suchen.

1. Dann beginne ich damit den den Suchbefehl zu schreiben.
2. Dann will ich das in einer Schleife wiederholen -> schreibe ich weiter/um
3. Will ich das auf mehrere Suchbegriffe ausweiten -> schreibe weiter / um

Aber um so ein Script wie deines zu machen muss man "anders denken". Wie genau gehst du da von den Gedanken heran?
Benutzeravatar
__blackjack__
User
Beiträge: 13071
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`__name__` ist ein Name. Da kann man über den Index in der Python-Dokumentation zu einer Beschreibung kommen: das ist an eine Zeichenkette mit dem Namen des Moduls gebunden. Ausser man führt das Modul als Programm aus, dann ist der Name an den Wert "__main__" gebunden. Der ``if``-Zweig wird also nur ausgeführt wenn man das Modul als Programm ausführt, aber nicht wenn man es einfach nur importiert.

Also mal abgesehen davon das man mit der Zeit Erfahrung sammelt und so ein paar Zeilen schon im Kopf formuliert hat bevor man sie schreibt, werden Programme nicht einfach so von Anfang bis Ende runtergeschrieben, sondern *entwickelt*. Also ein Stück Programm schreiben, testen ob das tut was es soll, und dann den nächsten Schritt. Wobei das auch durchaus so ablaufen kann, dass man erst Code schreibt um einen kleinen Teilschritt zu machen, und dann im nächsten Entwicklungsschritt eine Schleife darum legt um diesen Teilschritt für jeden Teil von Eingabedaten zu wiederholen.

Die Entwicklung kann also durchaus so aussehen:

Code: Alles auswählen

    # Die Position von einem Wort suchen und ausgeben:
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    print(text.index("Hänsel"))

    
    # Wort und Position ausgeben:
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    name = "Hänsel"
    print(name, "an Position", text.index(name))
    
    
    # Sinnvoll damit umgehen wenn das Wort nicht vorkommt:
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    name = "Klaus"
    try:
        index = text.index(name)
    except ValueError:
        pass
    else:
        print(name, "an Position", index)
    
    
    # Nicht nur den ersten Index ausgeben, sondern in einer Schleife alle finden
    # und ausgeben.
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    name = "Hänsel"
    index = 0
    while True:
        try:
            index = text.index(name, index)
        except ValueError:
            break

        print(name, "an Position", index)
        index += len(name)
    

    # Das ganze nicht nur für ein Wort, sondern für jedes Wort in einer Liste
    # wiederholen.
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    for name in ["Hänsel", "Gretel", "Hexe"]:
        index = 0
        while True:
            try:
                index = text.index(name, index)
            except ValueError:
                break

            print(name, "an Position", index)
            index += len(name)
Programmieren ist zu einem grossen Teil Probleme in kleinere Teilprobleme zu zerlegen, und die wieder in Teilprobleme zu zerlegen, solange bis die so klein sind, das man sie mit wenigen Zeilen Code lösen kann. Und dann testen man die Teillösungen, und wenn sie funktionieren, setzt man sie zu grösseren Teillösungen zusammen, bis das Gesamtproblem gelöst ist. Ab einer gewissen Komplexität, die gar nicht mal so hoch sein muss, zerlegt man den Code am besten auch in Funktionen. Die lassen sich besser isoliert testen, auch automatisiert, und auch wenn sie schon als Teillösung in einer grösseren (Teil-)Lösung verwendet werden. Beispiel:

Code: Alles auswählen

#!/usr/bin/env python3


def print_positions(name, text):
    index = 0
    while True:
        try:
            index = text.index(name, index)
        except ValueError:
            break

        print(name, "an Position", index)
        index += len(name)


def main():
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    for name in ["Hänsel", "Gretel", "Hexe"]:
        print_positions(name, text)


if __name__ == "__main__":
    main()
Wobei man üblicherweise auch die Programmlogik von der Benutzerinteraktion trennt, weil die `print_positions()`-Funktion lässt sich schlecht/nur umständlich automatisiert testen:

Code: Alles auswählen

#!/usr/bin/env python3
import pytest


def find_positions(name, text):
    index = 0
    while True:
        try:
            index = text.index(name, index)
        except ValueError:
            break

        yield index
        index += len(name)


def print_positions(name, text):
    for index in find_positions(name, text):
        print(name, "an Position", index)


def main():
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    for name in ["Hänsel", "Gretel", "Hexe"]:
        print_positions(name, text)


@pytest.mark.parametrize(
    "name, expected",
    [("Klaus", []), ("Hänsel", [0, 41]), ("Gretel", [11]), ("Hexe", [56])],
)
def test_find_positions(name, expected):
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    assert list(find_positions(name, text)) == expected


if __name__ == "__main__":
    main()
Testlauf:

Code: Alles auswählen

$ pytest forum21.py 
============================= test session starts ==============================
platform linux -- Python 3.8.0, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/bj
collected 4 items                                                              

forum21.py ....                                                          [100%]

============================== 4 passed in 0.01s ===============================
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

WOW! Vielen Dank für die Antwort. Die Mühe von dir weis ich zu schätzen. Ok. Ich arbeite das heute Abend schritt für schritt durch.
Namlus
User
Beiträge: 70
Registriert: Donnerstag 5. Januar 2023, 15:10

Vielen Dank nochmal. Heute bin ich dazu gekommen das ganze durchzuarbeiten.
Ich hätte noch 2 Fragen:
1. Du nutzt ein else ohne if? Bezieht sich das else dann auf das "except" (müsste es ja weil sonst würde das Script nicht funktionieren)?

Code: Alles auswählen

    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    name = "Klaus"
    try:
        index = text.index(name)
    except ValueError:
        pass
    else:
        print(name, "an Position", index)



2. Ich habe mein Script nach deiner Struktur "umgeschrieben" . Jedoch habe ich ein Problem mit den Variablen weil diese nicht übernommen werden. Hier auf Basis deines Scripts ein Beispiel. Ich habe ne Menge Variablen wie Zeitstempel, Durchlauf_ID, Fehlermeldung usw. die ich mir am Ende als Zusammenfassung ausgeben lasse. "return" funktioniert da leider genauso wenig wie "global"......

Code: Alles auswählen

anzahl_durchlauf = 1

def find_positions(name, text):
    index = 0
    while True:
        try:
            index = text.index(name, index)
        except ValueError:
            break

        yield index
        index += len(name)


def print_positions(name, text):
    for index in find_positions(name, text):
        print(name, "an Position", index)


def main():
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    for name in ["Hänsel", "Gretel", "Hexe"]:
        print_positions(name, text)
        anzahl_durchlauf =+ 1
        return anzahl_durchlauf


@pytest.mark.parametrize(
    "name, expected",
    [("Klaus", []), ("Hänsel", [0, 41]), ("Gretel", [11]), ("Hexe", [56])],
)
def test_find_positions(name, expected):
    text = "Hänsel und Gretel gingen durch den Wald. Hänsel sah die Hexe."
    assert list(find_positions(name, text)) == expected


if __name__ == "__main__":
    main()
    print (f"Das Script ist beendet. Es gab {anzahl_durchlauf} Durchläufe")



Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, try-Blöcke können auch einen else-Block haben, der dann ausgeführt wird, wenn keine Exception auftritt.
`find_positions` braucht einen Rückgabewert. Das sollte, wenn ich den Code richtig lese, eine Liste mit allen Positionen sein, an denen der Name gefunden wird.
In `main` macht das `return` in der for-Schleife keinen Sinn.
Und den Rückgabewert von `main` solltest Du ganz unten auch einer Variable zuweisen, damit Du den Wert auch weiterverwenden kannst (obwohl das unüblich ist, die print-Zeile sollte eigentlich in `main` stehen).
Antworten