Wort suchen was exakt auf das gesuchte passt

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
egon11
User
Beiträge: 365
Registriert: Mittwoch 14. Dezember 2016, 20:59

Hallo, ich möchte ein Wort suchen, was auch direkt ins Suchmuster passt.
Wenn ich "Auto" suche möchte ich nicht "Automaten" als Treffer bekommen.

Ich habe folgendes mal getestet:

Code: Alles auswählen

import re


my_liste = ["Auto", "Autobus", "Automaten"]

for i in my_liste:
    if re.search(r"Auto", i):
        print("Auto: " + i)
    elif re.search(r"Automaten", i):
        print("Automaten: " + 1)

Im "re" - Modul habe ich dazu nichts brauchbares gefunden -- oder überlesen--
Vielleicht könnt ihr mir eine kleine Hilfe geben wie man so etwas löst.

Gruß
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Du suchst re.match(), nicht re.search().

Noch einfacher wäre ein direkter Vergleich:

Code: Alles auswählen

for word in words:
    if word == "Auto":
        # ...
Oder mit einer Menge:

Code: Alles auswählen

words = set(["Auto", "Autobus", "Automaten"])
print("Auto" in words)
Zuletzt geändert von snafu am Dienstag 3. Februar 2026, 21:13, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 14301
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Warum denn dann `re` und nicht einfach `==`? Falls das Wort *in* einem Listenelement vorkommen können soll, dann ist das Beispiel schlecht gewählt, denn dafür reicht es ja nur ein Beispiel ohne die Liste zu zeigen und es sollte dann auch mehr als nur das Wort in dem zu durchsuchenden Text stehen. In dem Fall suchst Du wahrscheinlich „word boundary“, also r"\b" im regulären Ausdruck.

Und bitte nicht `my_liste` oder gar `i` für etwas das keine ganze Zahl ist.

Code: Alles auswählen

worte = ["Auto", "Autobus", "Automaten"]
for wort in worte:
    if wort in {"Auto", "Automaten"}:
        print(f"{wort}: {wort}")
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Außerdem sei der allseits bekannte Tipp erwähnt, einmal das Python Tutorial (Original | Übersetzung) durchzuarbeiten. Das hilft wirklich, wenn man ganz neu dabei ist.
egon11
User
Beiträge: 365
Registriert: Mittwoch 14. Dezember 2016, 20:59

Noch einfacher wäre ein direkter Vergleich:

Code: Alles auswählen

for word in words:
    if word == "Auto":
        # ...
Ich habe mich falsch ausgedrückt bzw mir ist ein Fehler bei der Beschreibung aufgefallen.
Also nochmal, ich lese eine Datei ein und speichere jede Zeile in eine Liste.
Danach iteriere ich die Liste und es sollen diese im #1 genannten Wörter gesucht werden.
Also in welcher Zeile kommt das Wort "Auto", das Wort "Autobus" und in welcher das Wort "Automat" vor.
Daher das ich die Sätze nicht kenne, kann ich den Vergleich mit "==" nicht bringen.
re.match sucht nur am Anfang.
Eine Variante wäre, jede Zeile nochmal bei jeden Leerzeichen zu splitten, um es so zu suchen (was ich hinbekommen hab).
Aber geht es auch einfacher?
Benutzeravatar
__blackjack__
User
Beiträge: 14301
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Was heisst einfacher? Und ist das an Leerzeichen aufteilen nicht _zu_ einfach, denn so wird man bei "Am Ende dieses Satzes steht ein Auto." das Auto nicht finden, weil "Auto" ≠ "Auto."

Deswegen erwähnte ich ja „word boundary“ bei regulären Ausdrücken. Allerdings würde das dann immer noch nicht helfen bei Sätzen wie "Bei diesem Glücksspielanbieter kann man Wetten auf Auto- und Pferderennen setzen." Da würde dann Auto erkannt, obwohl das eigentlich für "Autorennen" steht. Ähnlich falls beispielsweise "Automat" mit einem Bindestrich über zwei Zeilen getrennt wurde als "… Auto-", "mat …". Hier würde fälschlich "Auto" erkannt, "Automat" aber nicht.

Natürliche Sprache zu verarbeiten ist nicht so einfach.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Pedroski55
User
Beiträge: 37
Registriert: Freitag 25. Juli 2025, 00:20

Sag mal du willst herausfinden, wie oft Auto oder auto in einem langen Text vorkommt:

Code: Alles auswählen

import regex

my_liste = ["Auto", "Autobus", "Automaten", "automatisch",  "Autodidakt",  "Autonomo", "Autism", "autoreifen", "aufliegen"]
s = ' '.join(my_liste)
e = regex.compile(r'A(?=uto)')
f = regex.compile(r'a(?=uto)')
g = regex.compile(r'(a|A)(?=uto)')
zahl_A = len(e.findall(s)) # 5
zahl_a = len(f.findall(s)) # 2
zahl_alle = len(g.findall(s)) # 7
findall() gibt uns eine Liste zurück.

Man kann das auch auf anderer Art und Weise vollbringen!
Benutzeravatar
__blackjack__
User
Beiträge: 14301
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pedroski55: Was soll denn der positive lookahead in den Ausdrücken? Der ändert nichts am Ergebnis, verkompliziert nur unnötig die regulären Ausdrücke. Und das ist ziemlich deutlich nicht das was gefragt ist. Lies doch wenigstens die Frage(n) ordentlich durch.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

egon11 hat geschrieben: Dienstag 3. Februar 2026, 22:05 Also in welcher Zeile kommt das Wort "Auto", das Wort "Autobus" und in welcher das Wort "Automat" vor.
Also ich würde hier schon splitten und ein Set verwenden:

Code: Alles auswählen

LINES = [
    "Ich fahre lieber mit dem Auto statt mit dem Autobus",
    "Hier gibt es nichts zu sehen",
    "Der Automat schaltet sich automatisch aus",
]

NEEDLES = ["Auto", "Autobus", "Automat"]

def get_matches(lines, needles):
    needles = set(needles)
    for line_no, line in enumerate(lines, 1):
        words = set(line.split())
        if (matches := words & needles):
            yield line_no, sorted(matches)

def main():
    for line_no, matches in get_matches(LINES, NEEDLES):
        print(f"Line #{line_no}: {matches}")

if __name__ == "__main__":
    main()
Satzzeichen hab ich hier erstmal außer Acht gelassen.
egon11 hat geschrieben: Dienstag 3. Februar 2026, 22:05 Daher das ich die Sätze nicht kenne, kann ich den Vergleich mit "==" nicht bringen.
Doch, könntest du. Hierfür benötigst du eine innere Schleife, die für jedes Wort des Satzes über alle gesuchten Wörter iteriert und diese vergleicht. Wäre nur aufgrund des Laufzeitverhaltens nicht unbedingt zu empfehlen.
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Oder machst du eine Übung zu regulären Ausdrücken? Dann könnte man es so lösen:

Code: Alles auswählen

re.search(r"Auto(bus|mat)?(\W|$)", "Ich habe einen Autobus")
Dies findet Auto, Autobus sowie Automat, gefolgt von Whitespace oder dem Zeilen- bzw. String-Ende. Somit wäre "Autos" kein Treffer.
Benutzeravatar
__blackjack__
User
Beiträge: 14301
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Vorgabe war das "Auto" nur "Auto" finden soll, aber nicht "Automat" oder ähnliches. Nach "Automat" sollte extra gesucht werden. Und \b hatte ich ja schon zweimal vorgeschlagen. Kann man natürlich auch umständlich schreiben wenn man möchte. :-)
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

\b ist eine gute Idee. So ganz klar ist die Aufgabe IMHO noch nicht.

Dies hier gibt jedenfalls den ersten Treffer aus dem Pattern für die jeweilige Zeile aus:

Code: Alles auswählen

import re

LINES = [
    "Ich fahre lieber mit dem Auto statt mit dem Autobus",
    "Zwei Autos kann ich mir nicht leisten",
    "Der Automat schaltet sich automatisch aus",
]

PATTERN = "Auto(bus|mat)?"

def get_matches(lines):
    pattern = re.compile(rf"\b{PATTERN}\b")
    for line_no, line in enumerate(lines, 1):
        if match := pattern.search(line):
            yield line_no, match.group()

def main():
    for line_no, match in get_matches(LINES):
        print(f"Line #{line_no}: {match}")

if __name__ == "__main__":
    main()
Benutzeravatar
DeaD_EyE
User
Beiträge: 1317
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Wer hat schonmal einen regex programmatisch erzeugt?
Ich hab mir einfach einen Anwendungsfall ausgedacht.
Ich möchte Problem XY lösen.
Dann nehme ich einfach Regex
Mist, jetzt hab ich 2 Probleme

Code: Alles auswählen

import re


def make_regex(words: list[str], flags=0) -> re.Pattern:
    if not words:
        raise ValueError("words must not be empty.")

    if len(words) == 1:
        return re.compile(rf"\b{words[0]}\b", flags=flags)
    else:
        inner = "|".join(word for word in words)
        return re.compile(r"\b(" + inner + r")\b", flags=flags)

PS: [b][color=#FF0000]\b[/color][/b] ist wirklich sehr nützlich!!
def make_bold(text: str, regex: re.Pattern) -> str:
    new_text = []
    last = 0

    for m in regex.finditer(text):
        start, end = m.span()
        new_text.append(text[last:start])
        new_text.append("[b]")
        new_text.append(text[start:end])
        new_text.append("[/b]")
        last = end

    new_text.append(text[last:])
    return "".join(new_text)


words = ["Auto", "Autobus", "Automat", "Kreis", "Neustart"]
regex = make_regex(words)

text = (
    "Ich fahre lieber mit dem Auto statt mit dem Autobus\n"
    "Zwei Autos kann ich mir nicht leisten.\n"
    "Der Automat schaltet sich automatisch aus.\n"
    "Die Bushaltestelle ist nicht erreichbar.\n"
    "Für einen Neustart bitte im Kreis drehen.\n"
)

print(make_bold(text, regex))
Ausgabe als Zitat:
Ich fahre lieber mit dem Auto statt mit dem Autobus
Zwei Autos kann ich mir nicht leisten.
Der Automat schaltet sich automatisch aus.
Die Bushaltestelle ist nicht erreichbar.
Für einen Neustart bitte im Kreis drehen.
Man kann auch Flags setzen:

Code: Alles auswählen

print(make_bold(text.lower(), make_regex(words, flags=re.IGNORECASE)))
ich fahre lieber mit dem auto statt mit dem autobus
zwei autos kann ich mir nicht leisten.
der automat schaltet sich automatisch aus.
die bushaltestelle ist nicht erreichbar.
für einen neustart bitte im kreis drehen.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das kann man auch mit re.sub() und dem Einsatz von Backreferences haben, wobei ich das nach wie vor etwas tunen würde, wenn gleiche Wortanfänge vorliegen:

Code: Alles auswählen

import re

text = """\
Ich fahre lieber mit dem Auto statt mit dem Autobus.
Zwei Autos kann ich mir nicht leisten.
Der Automat schaltet sich automatisch aus.
Die Bushaltestelle ist nicht erreichbar.
Für einen Neustart bitte im Kreis drehen.
"""

words = "Auto(bus|mat)?", "Kreis", "Neustart"

pattern = r"\b({})\b".format("|".join(words))
print(re.sub(pattern, r"[b]\1[/b]", text))
DeaD_EyE hat geschrieben: Mittwoch 4. Februar 2026, 19:18
Ich möchte Problem XY lösen.
Dann nehme ich einfach Regex
Mist, jetzt hab ich 2 Probleme
Ich würde sagen, das hängt vom Problem ab und wie gut man darin ist, reguläre Ausdrücke zu formulieren und die passenden Funktionen zu nutzen.
Sirius3
User
Beiträge: 18358
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: wenn ein Sonderfall gar kein Sonderfall ist, braucht man ihn auch nicht gesondert behandeln. Ein Generator-Ausdruck der nichts am Input ändert, kann man auch weglassen.
Du weißt, wie man f-Strings anwendet, warum verwendest Du dann Stringzusammenstückeln mit +?
Damit wird die Funktion deutlich übersichtlicher:

Code: Alles auswählen

def make_regex(words, flags=0):
    if not words:
        raise ValueError("words must not be empty.")
    inner = "|".join(words)
    return re.compile(rf"\b({inner})\b", flags=flags)
Und weil es hier noch niemand angesprochen hat: wenn man unbekannte Strings in regulären Ausdrücken verwenden will, sollte man sie per re.escape schützen:

Code: Alles auswählen

def make_regex(words, flags=0):
    if not words:
        raise ValueError("words must not be empty.")
    inner = "|".join(map(re.escape, words))
    return re.compile(rf"\b({inner})\b", flags=flags)
@snafu: Performance-mäßig ist es ziemlich egal, wie Du den regulären Ausdruck schreibst, sowohl `Auto(mat|bus)` als auch `Automat|Autobus` führen zum selben regulären Automaten.
Benutzeravatar
snafu
User
Beiträge: 6928
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und was noch dazu kommt: Als Spielerei ist es ganz nett, eine Wörterliste als Regex zusammen zu führen. Es bläht den resultierenden Ausdruck aber potenziell ziemlich auf. Wie ich schon am Anfang geschrieben hatte, rate ich hier zum zeilenweisen Splitten der Wörter. Dies kann man durchaus mit dem re-Modul umsetzen, wenn man mehr als nur zwischen den Leerzeichen trennen möchte. BJ hatte hier schon ein paar Beispiele gebracht. Die Suche nach Treffern würde ich dann jedenfalls über eine geeignete Datenstruktur erledigen.

Einfach nur als Disclaimer gemeint, dass die Aufgabenstellung IMHO keinen Fall für eine reine Regex-Lösung darstellt.
Antworten