Hallo Zusammen,
erstmal ein freundliches Hallo in die Runde. Ich bin Doerpi und neu hier im Forum und im Bereich Python Programmierung. Ich hoffe durch dieses Forum und die Community einen hilfreichen Austausch zu erhalten und meine Programmierfaehigkeiten zu verbessern. Also schonmal ein nettes Danke an alle!
So jetzt zu meinem Problem:
Ich habe in einem Verzeichnis mehrere .txt Dateien, welche alle mehrere 100 Zeilen mit Informationen enthalten (Name + Mitarbeiternummer).
Ich moechte diese ganzen .txt Dateien einlesen und in einer einzigen Datei zusammenfassen und entweder waehrenddessen oder danach die Zeilen abgleicht und doppelte Eintraege loescht.
Ich arbeite derzeit auf einem Manjaro/Linux mit Visual Code Studio mit neuster Python Version.
Leider stehe ich absolut am Anfang und habe keinen Ansatz dieses Problem anzugehen.
Ich bin fuer jede Hilfe Dankbar!
Gruesse
Doerpi
Textdateien auslesen, zusammenfuehren und doppelte Eintraege loeschen
Ein Anfang ist das pathlib-Modul, und dort vor allem die Path.glob-Methode, mit der du dir auch rekursiv alle Eintraege die einem bestimmten Muster entsprechen auflisten lassen kannst.
Fuer die Weiterverarbeitung empfehlen sich dann ggf. das csv-Modul, und die Datenstruktur set, um Dubletten zu vermeiden. Beides gut beschrieben in der Python-Dokumentation.
Code: Alles auswählen
import pathlib
import sys
BASE = pathlib.Path(sys.prefix)
for path in BASE.glob("**/*.py"):
print(path)
Das zugeordnete Verzeichnis ist "sys.prefix" in diesem Fall, kann aber auch sein, was immer du willst. Kann ich ja nicht wissen, was sonst es sein soll.
Und was denkst du ist "*.py"? Und hast du mal in der Dokumentation die Beschreibung der glob-Methode angeschaut? Was genau daran ist dir unklar?
Und was denkst du ist "*.py"? Und hast du mal in der Dokumentation die Beschreibung der glob-Methode angeschaut? Was genau daran ist dir unklar?
- __blackjack__
- User
- Beiträge: 14052
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Doerpi: Wobei man sich am besten vorher auch genauere Gedanken macht was ”doppelte Einträge” sind. Wenn sowohl Name als auch Mitarbeiternummer gleich sind, ist das ja kein Problem, aber wie sieht es bei gleicher Mitarbeiternummer aber anderem Namen aus? So etwas kann ja ganz normal beispielsweise durch Heirat entstehen.
Um aus Iteratoren über die Zeilen der einzelnen Dateien einen über alle Zeilen zu machen, bietet sich `itertools.chain.from_iterable()` an.
Wenn es einfach nur ein 1:1 Abgleich der ganzen Zeile sein soll, würde ich noch gerne auf das externe Modul `more_itertools` und da die `unique_everseen()`-Funktion verweisen.
Beim öffnen von Textdateien sollte man immer explizit eine Kodierung angeben.
Du lässt Dir `path` anzeigen damit Du weisst was da ausgegeben wird wenn Du das Beispiel laufen lässt, damit Du siehst was das Beispiel macht. An der Stelle musst Du dann natürlich irgendwas machen was für *Dich* sinnvoll ist.
Edit: Für das Heimatverzeichnis des Benutzers unter dem das ausgeführt wird, hat `Path` übrigens auch etwas.
Um aus Iteratoren über die Zeilen der einzelnen Dateien einen über alle Zeilen zu machen, bietet sich `itertools.chain.from_iterable()` an.
Wenn es einfach nur ein 1:1 Abgleich der ganzen Zeile sein soll, würde ich noch gerne auf das externe Modul `more_itertools` und da die `unique_everseen()`-Funktion verweisen.
Beim öffnen von Textdateien sollte man immer explizit eine Kodierung angeben.
Du lässt Dir `path` anzeigen damit Du weisst was da ausgegeben wird wenn Du das Beispiel laufen lässt, damit Du siehst was das Beispiel macht. An der Stelle musst Du dann natürlich irgendwas machen was für *Dich* sinnvoll ist.
Edit: Für das Heimatverzeichnis des Benutzers unter dem das ausgeführt wird, hat `Path` übrigens auch etwas.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Du musst zur Pfad-Angabe einen String verwenden, also "/home/doerpi/Dokumente". Und das der Pfad ausgegeben wird dient doch erstmal nur zur Kontrolle, ob der Code tut, was er tun soll. Wenn du das nicht machst, woher weisst du dann, was ueberhaupt passiert ist?
also ja es soll ein 1:1 abgleich der Zeilen durchgefuehrt werden.
also ich habe mal den oberen Teil getestet:
import pathlib
import sys
BASE = pathlib.Path("/home/doerpi/Downloads")
for path in BASE.glob("**/*.txt"):
print(path)
und es kam dabei dieser Fehler:
PyTh0n]$ /usr/bin/python /home/doerpi/Dokumente/Github/PyTh0n/VerzeichnisTest.py
File "/home/doerpi/Dokumente/Github/PyTh0n/VerzeichnisTest.py", line 7
print(path)
^
IndentationError: expected an indented block
also ich habe mal den oberen Teil getestet:
import pathlib
import sys
BASE = pathlib.Path("/home/doerpi/Downloads")
for path in BASE.glob("**/*.txt"):
print(path)
und es kam dabei dieser Fehler:
PyTh0n]$ /usr/bin/python /home/doerpi/Dokumente/Github/PyTh0n/VerzeichnisTest.py
File "/home/doerpi/Dokumente/Github/PyTh0n/VerzeichnisTest.py", line 7
print(path)
^
IndentationError: expected an indented block
Dann stimmt die Einrückung wohl nicht. Am besten auch immer deinen Code hier im Forum in CodeTags packen, damit die Einrückung (in Python laut Konvention 4 Leerzeichen) da bleibt. (Im vollständigen Editor auf das </> Symbol)
Code: Alles auswählen
import pathlib
import sys
BASE = pathlib.Path("/home/doerpi/Downloads")
for path in BASE.glob("**/*.txt"):
print(path)
Du bist wirklich ganz, ganz am Anfang mit Python, oder? Einrückungen haben eine Bedeutung in Python. Vielleicht magst du erst mal anhand des Tutorials die Grundlagen lernen bevor du dich an komplexere Dinge machst. Ich geh ja auch nicht her und sage: "Ich habe jetzt angefangen einen Lötkolben zu benutzen. Wie baue ich damit ein Containerschiff zusammen?"Doerpi hat geschrieben: Donnerstag 13. Februar 2020, 14:59 IndentationError: expected an indented block
ok das war der fehler, aber jetzt wenn ich das script laufen lasse gibt er nichts aus, es laeuft einfach ohne Rueckmeldung durch
desweiteren wuerde ich gerne den Tip mit dem `more_itertools` Modul versuchen, muss ich das vorher importieren?
desweiteren wuerde ich gerne den Tip mit dem `more_itertools` Modul versuchen, muss ich das vorher importieren?
Ja ich bin wirklich ganz am Anfang. Ich mache nebenbei gerade einen Python Kurs und wollte mir mit dieser Aufgabe mein erstes Ziel setzen, da ich dachte so eine zusammenfuehrung mehrerer Textdateien sei ein einfacher Schritt/me hat geschrieben: Donnerstag 13. Februar 2020, 15:14Du bist wirklich ganz, ganz am Anfang mit Python, oder? Einrückungen haben eine Bedeutung in Python. Vielleicht magst du erst mal anhand des Tutorials die Grundlagen lernen bevor du dich an komplexere Dinge machst. Ich geh ja auch nicht her und sage: "Ich habe jetzt angefangen einen Lötkolben zu benutzen. Wie baue ich damit ein Containerschiff zusammen?"Doerpi hat geschrieben: Donnerstag 13. Februar 2020, 14:59 IndentationError: expected an indented block
ok habe das angepasst aber das script laeuft dennoch einfach durch ohne eine InfoJankie hat geschrieben: Donnerstag 13. Februar 2020, 15:33 Wenn du nach "**/*.txt" suchst, wird nur in Unterordnern von "/home/doerpi/Downloads" gesucht. Wenn du in Downloads direkt suchen willst musst du "*.txt" verwenden.
- __blackjack__
- User
- Beiträge: 14052
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Doerpi: Definiere einfach — wenn man programmieren kann, dann ist das nicht schwer. Mit den richtigen Werkzeugen auch recht kurz. Aber dazu muss man programmieren lernen und die Werkzeuge (kennen)lernen. Wie schwer das dann ist, ist recht individuell.
`more_itertools` muss man importieren, aber da es nicht Teil der Standardbibliothek ist auch erst einmal installieren. Die `unique_everseen()`-Funktion ist aber AFAIK ein ”Rezept” aus der Dokumentation des `itertools`-Moduls aus der Standardbibliothek. Und man kann sich das Wissen um so eine Funktion zu schreiben natürlich auch selbst erarbeiten. Das geht mit den Grundlagen über den `set`-Datentyp, den __deets__ bereits erwähnt hat.
Ungetestet:
`more_itertools` muss man importieren, aber da es nicht Teil der Standardbibliothek ist auch erst einmal installieren. Die `unique_everseen()`-Funktion ist aber AFAIK ein ”Rezept” aus der Dokumentation des `itertools`-Moduls aus der Standardbibliothek. Und man kann sich das Wissen um so eine Funktion zu schreiben natürlich auch selbst erarbeiten. Das geht mit den Grundlagen über den `set`-Datentyp, den __deets__ bereits erwähnt hat.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
from contextlib import closing
from pathlib import Path
from more_itertools import unique_everseen
BASE_PATH = Path.home() / "Dokumente"
ENCODING = "ascii"
def iter_lines(file_paths):
for path in file_paths:
with path.open("r", encoding=ENCODING) as file:
yield from file
def main():
text_file_paths = (
path for path in BASE_PATH.rglob("*.txt") if path.is_file()
)
with closing(iter_lines(text_file_paths)) as lines:
with open("result.txt", "w", encoding=ENCODING) as file:
file.writelines(unique_everseen(lines))
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Was enhaelt es denn sonst? Ich finde ja in https://en.wikipedia.org/wiki/ASCII#/me ... _chart.png eine ganze Menge von Zahlen und Zeichen. Es fehlen aber zB Umlaute oder Sonderzeichen die eben nicht in ASCII sind. Sind solche in deinen Daten?
Umlaute koennten enthalten sein, Sonderzeichen eher nicht aber koennte ich es nicht so erweitern um sicher zu sein:
#!/usr/bin/env python3
from contextlib import closing
from pathlib import Path
from more_itertools import unique_everseen
BASE_PATH = Path.home() / "Dokumente"
ENCODING = "ascii, digits, punctuation"
def iter_lines(file_paths):
for path in file_paths:
with path.open("r", encoding=ENCODING) as file:
yield from file
def main():
text_file_paths = (
path for path in BASE_PATH.rglob("*.txt") if path.is_file()
)
with closing(iter_lines(text_file_paths)) as lines:
with open("result.txt", "w", encoding=ENCODING) as file:
file.writelines(unique_everseen(lines))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
from contextlib import closing
from pathlib import Path
from more_itertools import unique_everseen
BASE_PATH = Path.home() / "Dokumente"
ENCODING = "ascii, digits, punctuation"
def iter_lines(file_paths):
for path in file_paths:
with path.open("r", encoding=ENCODING) as file:
yield from file
def main():
text_file_paths = (
path for path in BASE_PATH.rglob("*.txt") if path.is_file()
)
with closing(iter_lines(text_file_paths)) as lines:
with open("result.txt", "w", encoding=ENCODING) as file:
file.writelines(unique_everseen(lines))
if __name__ == "__main__":
main()
Bitte den Code in die dafuer vorgesehenen Code-Tags setzen, denn so gehen die (wie du ja heute schon gelernt hast) imminent wichtigen Einrueckungen verloren.
Und nein, DAS geht nicht - du kannst nicht einfach ein paar ausgedachte wunsch-werte anhaengen, und dann geht das alles. Es gibt eine ganz wohldefinierte Menge an Encodings, wie zB ascii, utf-8, latin1. Du musst selbst wissen oder erfragen, welches Encoding deinen Daten zugrunde liegt, und DAS dann benutzen. Oder heuristisch arbeiten, wenn die Daten nicht "sauber" sind. Also zB erstmal mit UTF-8 probieren, und wenn das in die Hose ging, mit latin1 weiter machen.
Und nein, DAS geht nicht - du kannst nicht einfach ein paar ausgedachte wunsch-werte anhaengen, und dann geht das alles. Es gibt eine ganz wohldefinierte Menge an Encodings, wie zB ascii, utf-8, latin1. Du musst selbst wissen oder erfragen, welches Encoding deinen Daten zugrunde liegt, und DAS dann benutzen. Oder heuristisch arbeiten, wenn die Daten nicht "sauber" sind. Also zB erstmal mit UTF-8 probieren, und wenn das in die Hose ging, mit latin1 weiter machen.
- __blackjack__
- User
- Beiträge: 14052
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Ich hatte ASCII erst mal als kleinsten gemeinsamen Nenner gewählt damit das auf die Nase fällt wenn da etwas anderes als ASCII in den Dateien vorkommt. Denn dann müsste man wissen wie die Dateien kodiert sind, und das müsstest *Du* dann machen, denn ich kann das ja nicht wissen.
"ascii, digits, punctuation" ist jedenfalls kein gültiger Kodierungsname, was man auch laut und deutlich gesagt bekommt:
Noch eine Anmerkung zu Heuristiken: Raten funktioniert nicht wirklich gut. Man kann ganz gut erkennen ob etwas *nicht* UTF-8 kodiert ist, weil nicht alle Bytefolgen gültiges UTF-8 sind, aber viele Kodierungen die einfach einzelne Bytewerte auf Zeichen abbilden, fressen auch problemlos Bytefolgen die *nicht* in der Kodierung vorliegen. Die Zeichen stimmen dann halt einfach nicht, das kann aber nur ein Mensch erkennen der weiss was da eigentlich stehen müsste anstelle der falschen Zeichen.
"ascii, digits, punctuation" ist jedenfalls kein gültiger Kodierungsname, was man auch laut und deutlich gesagt bekommt:
Code: Alles auswählen
In [15]: f = Path("test.txt").open(encoding="ascii, digits, punctuation")
---------------------------------------------------------------------------
LookupError Traceback (most recent call last)
<ipython-input-15-653b641a738e> in <module>
----> 1 f = Path("test.txt").open(encoding="ascii, digits, punctuation")
/usr/lib/python3.6/pathlib.py in open(self, mode, buffering, encoding, errors, newline)
1181 self._raise_closed()
1182 return io.open(str(self), mode, buffering, encoding, errors, newline,
-> 1183 opener=self._opener)
1184
1185 def read_bytes(self):
LookupError: unknown encoding: ascii, digits, punctuation
“Vir, intelligence has nothing to do with politics!” — Londo Mollari