Python und txt

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.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Liebe alle,
ich bin noch ein Python-Frischling und habe immer das gleiche Problem.
Wenn ich ein py-Programm z.B. eine Liste aus einer txt-Datei auslesen lassen will,
bekomme ich immer die Fehlermeldung "No such file or directory",
dabei liegt die txt-Datei im gleichen Ordner wie die Python-Datei.
Nun habe ich es damit versucht, den genauen Pfad anzugeben,
ein kleines "r" davorzuschreiben, mit 2 oder 3 Backslashs zu arbeiten
und habe es bereits mit UTF8 mit und ohne BOM versucht.
Nichts will helfen. Vielleicht könnt ihr mir einen guten Rat geben.

Ich habe die Fehlermeldung in euer Suchfeld eingegeben und hatte den Eindruck,
dass da zwar einiges matcht, hatte aber den Eindruck, dass nichts dort
mein Problem wirklich umreißt. Falls ich hier einen unnötigen Thread aufgetan habe,
bitte ich um Verzeihung.

Herzliche Grüße
von
Andreas
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das gleiche Verzeichnis hat keinen unmittelbaren Einfluss auf den Pfad. Denn ein relativer Pfad

Code: Alles auswählen

with open("beispieldatei.txt") as inf: ...
wird relativ zum Arbeitsverzeichnis zu einem absoluten gewandelt. Nur weil beispieldatei.txt neben dem Skript liegt, zeigt das Arbeitsverzeichnis nicht notwendigerweise auf das Verzeichnis, in dem beide sind, und dann kommt es eben zu dem Fehler.

Sonst muss - wie du schon selbst sagst - der Pfad absolut angegeben werden. Warum das bei dir nicht geht, kann man nicht ferndiagnostizieren. Zeig den genauen Pfad im konkreten Skript, die genaue Fehlermeldung, und alle weiteren relevanten Informationen wie Python-Version, in welcher Umgebung das ausgefuehrt wird, etc.

BOM gibt's bei Python und seinen literalen nicht.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Lieber deets,
herzlichen Dank für die schnelle Antwort.
Inzwischen habe ich den Pfad nochmal ganz genau angegeben
und es ist eine Unicode-Sache draus geworden:

Hier ist der Code:

# Öffnen der Datei zum Lesen
with open("c:\Users\User\Desktop\MALDIX K.I\GPT\terms.txt") as f:
# Lesen aller Zeilen in die Liste
lines = f.readlines()

# Durchlaufen der Liste und Setzen von Anführungszeichen um jeden Begriff und Entfernen von Underscores
quoted_terms = []
for line in lines:
quoted_terms.append('"' + term + '"')
term = line.strip().replace("_", " ")


# Sortieren der Liste
quoted_terms.sort()

# Öffnen der Ausgabedatei zum Schreiben
with open("sorted_terms.txt", "w") as f:
# Schreiben der sortierten Liste in die Ausgabedatei
for term in quoted_terms:
f.write(term + "\n")

Und hier die Fehlermeldung:

File "c:\Users\User\Desktop\MALDIX K.I\GPT\Anführungszeichen alphabetisch ohne Unterstrich Liste.py", line 2
with open("c:\Users\User\Desktop\MALDIX K.I\GPT\terms.txt") as f:
^
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Naja, das ist halt der Klassiker. Du musst bei normalen Strings nun mal \\ für einen slash angeben. Sonst leitet \ eine Escape-Sequenz ein. Und \U halt für Unicode. Und \t für tab. Oder du benutzt eben raw strings. Mit r vor dem “.
Sirius3
User
Beiträge: 18261
Registriert: Sonntag 21. Oktober 2012, 17:20

\ ist das Escapezeichen bei Literalen Strings, und \U leitet eben ein Unicodepoint ein, also besser / als Pfadtrenner benutzen, dann gibt es das Problem nicht.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Mit r, \\, sogar mit \\\ hatte ich es auch schon versucht, aber mit / klappt es. Ganz herzlichen Dank deets und Sirius 3 :) Andreas
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mit \\ wuerde es auch gehen, du hast es dann irgendwie nicht korrekt gemacht:

Code: Alles auswählen

print("c:\\Users\\User\\Desktop\\MALDIX K.I\\GPT\\terms.txt")
Ausgabe:

Code: Alles auswählen

c:\Users\User\Desktop\MALDIX K.I\GPT\terms.txt
Aber wenn es mit / geht, ist natuerlich kein grund, da nochmal ran zu gehen.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Ja, ist sehr gut möglich, dass ich irgendwo nachlässig geschrieben habe. Danke nochmal. Andreas
Benutzeravatar
__blackjack__
User
Beiträge: 14021
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Inhaltliche Anmerkungen: Kommentare sollten dem Leser einen Mehrwert über den Code bieten. Faustregel: Ein Kommentar beschreibt nicht was der Code macht, denn das steht dort bereits als Code, sondern warum er das so macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in der Regel was in der Dokumentation von Python oder den verwendeten Bibliotheken steht.

Namen sollten nicht kryptisch abgekürzt werden. Wenn man `file` meint, sollte man nicht nur `f` schreiben.

Die `readlines()`-Methode braucht man eigentlich fast nie. Man kann da die generischere `list()`-Funktion nehmen was die Elemente von jedem iterierbaren Objekt in einer Liste sammelt, oder diese oft unnötige Zwischenliste gar nicht erstellen, weil das Dateiobjekt ja iterierbar ist und die einzelnen Zeilen liefert:

Code: Alles auswählen

    with open("c:/Users/User/Desktop/MALDIX K.I/GPT/terms.txt") as lines:
        quoted_terms = []
        for line in lines:
            quoted_terms.append('"' + term + '"')
            term = line.strip().replace("_", " ")
Wobei das so rum gar nicht laufen kann, wenn hier wird `term` verwendet bevor es definiert wurde. Und wenn man das in *einen* Ausdruck steckt:

Code: Alles auswählen

    with open("c:/Users/User/Desktop/MALDIX K.I/GPT/terms.txt") as lines:
        quoted_terms = []
        for line in lines:
            quoted_terms.append('"' + line.strip().replace("_", " ") + '"')
Kann man aus der Schleife eine „list comprehension“ machen:

Code: Alles auswählen

    with open("c:/Users/User/Desktop/MALDIX K.I/GPT/terms.txt") as lines:
        quoted_terms = [
            '"' + line.strip().replace("_", " ") + '"' for line in lines
        ]
Wobei man sich die zusätzliche Zeile für das sortieren sparen kann, wenn man diese Elemente gleich in die `sorted()`-Funktion füttert:

Code: Alles auswählen

    with open("c:/Users/User/Desktop/MALDIX K.I/GPT/terms.txt") as lines:
        quoted_terms = sorted(
            '"' + line.strip().replace("_", " ") + '"' for line in lines
        )
Nun noch das Zeilenende-Zeichen schon vor dem Sortieren hinzufügen, und das gesamte Programm ist nur noch das hier:

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    with open("c:/Users/User/Desktop/MALDIX K.I/GPT/terms.txt") as lines:
        with open("sorted_terms.txt", "w") as output_file:
            output_file.writelines(
                sorted(
                    '"' + line.strip().replace("_", " ") + '"\n'
                    for line in lines
                )
            )


if __name__ == "__main__":
    main()
Bei Textdateien sollte man beim Öffnen die Kodierung explizit angeben, sonst muss man hoffen, dass die ”geratene” Kodierung zu der tatsächlichen passt.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Ganz herzlichen Dank, Blackjack :)
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Nun noch eine Nachfrage, bei der wahrscheinlich endgültig klar werden wird, was für ein Frischling ich bin.

Die binäre Liste, die ich mit den Sachen oben hergestellt habe, wollte ich nun einem "Berufs-Erkenner" in Python zur Verfügung stellen,
statt mir aber auf die Eingabe "Ich bin Schreiner." (das in meiner "binären Liste" zu finden ist und deshalb gematcht werden soll) zu "Ich bin @$@(Schreiner)." umzumodeln, wiederholt es einfach die Eingabe. Sieht jemand, woran das liegt?


import re

filename = "c:/Users/User/Desktop/MALDIX K.I/GPT/binär-liste-berufe.txt"

term = input("Bitte geben Sie einen Satz ein, in dem ein Beruf oder keiner zu finden ist: ")

with open(filename, "r") as file:
terms = file.read().splitlines()

terms.sort()

# Start- und Endindizes für den Bereich, in dem wir suchen
start_index = 0
end_index = len(terms) - 1

# Durchführen der binären Suche
while start_index <= end_index:
# Bestimmen des mittleren Indexes
mid_index = (start_index + end_index) // 2
# Vergleichen des gesuchten Begriffs mit dem Begriff im mittleren Index
if re.search(r"\b" + terms[mid_index] + r"\b", term, re.IGNORECASE):
# Begriff gefunden
term = re.sub(r"\b" + terms[mid_index] + r"\b", "@$@(" + terms[mid_index] + ")", term, flags=re.IGNORECASE)
print(term)
break
elif terms[mid_index].lower() < term.lower():
# Suche im rechten Bereich fortsetzen
start_index = mid_index + 1
else:
# Suche im linken Bereich fortsetzen
end_index = mid_index - 1

else:
print(term)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was soll denn eine "binaere Liste" sein? Der Begriff ist mir nicht bekannt. Meinst du binaere Suche in einer Liste? Dafuer gibt es schon fertig das bisect-Modul. Was da genau umgemodelt werden soll, ist mir unklar. Sollen das irgendwelche wild-cards sein, oder was ist der Zweck dieser Sonderzeichensammlung?
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

War eine kleine Zusammenziehung für "Liste für eine binäre Suche." :) Der Zweck der Sonderzeichensammlung ist der Versuch, eine "Ontologie der Bedürfnisse" ans Laufen zu kriegen, die Adam Pease von SUMO erfreulicherweise "intriguing" nennt. Vielen Dank für den Hinweis aufs bisect-Modul.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Leider gibt der folgende Code auf "Ich bin Schreiner." nur aus: "Ich habe in dem Satz keinen Beruf gefunden." Sitze wahrscheinlich auf den Augen.

Code: Alles auswählen

import re
import bisect

# Dateinamen der Liste mit den Berufen
filename = "c:/Users/User/Desktop/MALDIX K.I/GPT/binär-liste-berufe.txt"

# Text-Eingabe abfragen
term = input("Bitte geben Sie einen Satz ein, in dem ein Beruf zu finden sein kann: ")

# Liste mit den Berufen aus der Datei einlesen
with open(filename, "r") as file:
    terms = file.read().splitlines()

# Sortieren der Liste
terms.sort()

# Indizes für den Bereich, in dem wir suchen
i = bisect.bisect_left(terms, term)

# Durchführen der binären Suche
if i != len(terms) and terms[i] == term:
    # Begriff gefunden
    term = re.sub(r"\b" + terms[i] + r"\b", "@$@(" + terms[i] + ")", term, flags=re.IGNORECASE)
    print(term)
else:
    # Begriff nicht gefunden
    print("Ich habe im Satz keinen Beruf gefunden.")
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst ja auch deinen Term in Worte zerlegen, und die einzeln suchen. Deine momentanes Vorgehen basiert auf exakter Gleichheit. Da ist keine Unschärfe oder extra Drumrum erlaubt.
Benutzeravatar
__blackjack__
User
Beiträge: 14021
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mir ist das mit der Liste auch noch nicht so ganz klar. Warum ist das nicht einfach ein `set()`? Momentan wird mit dem `i` ja nichts anderes gemacht als da wieder auf `terms` zuzugreifen. Was im Erfolgsfall immer den gleichen Wert ergibt wie `term`.

Wenn ich das richtig verstanden habe wäre es wohl sinnvoller das ganze einfach komplett mit `re.sub()` zu erledigen und aus dem Begriffen aus der Datei einen regulären Ausdruck zu basteln. `re.escape()` ist da nützlich um das robust gegen irgendwelche Sonderzeichen in den Suchbegriffen zu machen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Ich habe es mal mit dem hier und ein paar Varianten versucht, komme aber immer noch nicht weiter. "Stallblindheit" nehme ich an. Noch immer ist die Ausgabe zu "Ich bin Schreiner." nicht "Ich bin @$@(Schreiner)." wie ich hoffte.

Code: Alles auswählen

import re
import bisect

# Dateinamen der Liste mit den Berufen
filename = "c:/Users/User/Desktop/MALDIX K.I/GPT/binär-liste-berufe.txt"

# Text-Eingabe abfragen
term = input("Bitte geben Sie einen Satz ein, in dem ein Beruf oder keiner zu finden ist: ")

# Liste mit den Berufen aus der Datei einlesen
with open(filename, "r") as file:
    terms = file.read().splitlines()

# Sortieren der Liste
terms.sort()

# Zerlegen des Satzes in eine Liste von Worten
words = term.split()

# Durchlaufen der Liste der Worte und Vergleich mit der Liste der Berufe
for i, word in enumerate(words):
    # Indizes für den Bereich, in dem wir suchen
    j = bisect.bisect_left(terms, word)
    
    # Durchführen der binären Suche
    if j != len(terms) and terms[j] == word:
        # Begriff gefunden
        words[i] = "@$@(" + terms[j] + ")"

# Zusammensetzen des Satzes aus der Liste der Worte
output = " ".join(words)
print(output)
Und zu Blackjack: Wenn ich hiermit versuche, ist das Ergebnis auch nicht anders.

Code: Alles auswählen

import re

# Dateinamen der Liste mit den Berufen
filename = "c:/Users/User/Desktop/MALDIX K.I/GPT/binär-liste-berufe.txt"

term = input("Bitte geben Sie einen Satz ein, in dem ein Beruf oder keiner zu finden ist: ")

# Liste mit den Berufen aus der Datei einlesen
with open(filename, "r") as file:
    terms = file.read().splitlines()

# Erstellen eines regulären Ausdrucks aus der Liste der Berufe
pattern = "\\b(" + "|".join(map(re.escape, terms)) + ")\\b"

# Anwenden des regulären Ausdrucks auf den Satz
output = re.sub(pattern, "@$@(\g<1>)", term, flags=re.IGNORECASE)
print(output)
In den Suchen sind auch keine Sonderzeichen zu finden, Blackjack. Das eine ist eine sehr große Liste mit Berufen, das andere sind die echtsprachlichen User-Eingaben. Sonderzeichen sollen erst zur Kennzeichnung der Tatsache gesetzt werden, dass ein Beruf gefunden worden ist. Wird später für die Verarbeitung in der Ontologie der Bedürfnisse gebraucht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann ist das alles so nicht zielführend. Wenn ist es hilfreicher, alles Berufe in der Eingabe zu suchen. Und noch besser sind Verfahren des Natural Language Processing wie Trigramme etc, um auch gewisse Fehl- oder Anderschreibungen zum Erfolg zu führen.
Andreas22
User
Beiträge: 31
Registriert: Donnerstag 5. Januar 2023, 16:51

Ja, Deets, das ist schon ein Argument, ich wollte halt durch die binäre Suche verhindern, noch eigens etwas wie Spacy mit Berufen trainieren zu müssen.
Benutzeravatar
__blackjack__
User
Beiträge: 14021
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Andreas22: Diese binäre Suche ist völliger Unsinn. Das löst hier überhaupt nichts und macht einfach nur alles komplizierter, denn diese Liste wird nur wie ein `set()` verwendet um zu prüfen ob eine Zeichenkette enthalten ist oder nicht. Das wäre mit einem `set()` einfacher *und* effizienter.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten