Seite 1 von 1
Datei auslesen
Verfasst: Donnerstag 18. April 2019, 15:00
von mjleonir
Hallo,
Ich bin relativ neu in der "Programmierszene" oder zumindest Einsteiger.
Ich lerne zurzeit ein wenig Python und wollte ein Programm schreiben, welches verschiedene Sprachen unterstützt und somit aus der dafür vorhergesehenen Datei die einzelnen Zeilen Text ausliest.
Der Code sieht bisher so aus:
Code: Alles auswählen
lang_input = input("Sprache?")
lang = 'lang/'+lang_input+'.txt'
#10 column
with open(lang, 'r') as f:
f_contents = f.read().split('\n')[9]
print(f_contents)
#7 column
with open(lang, 'r') as f:
f_contents = f.read().split('\n')[6]
print(f_contents)
(Bei #10 column wird die 10. Zeile ausgelesen, bei #7 column die 7.)
Meine Frage war nun, ob man diesen Code nicht "kürzer" gestalten kann, ich habe mir das so ähnlich vorgestellt:
f_contents = f.read().split('\n')
[9 and 6]
print(f_contents)
Nur dass das so eben nicht klappt, da er dann nur Zeile 7 (6) ausgibt, da f_contents natürlich nur einen Wert gleichzeitig haben kann.
Hat da jemand vielleicht einen schönen Vorschlag?

Für einen ganz neuen Ansatz wäre ich natürlich auch offen.
Hier nochmal ein Bild wie das ganze dann aussieht wenn der Code ausgeführt wird:

Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 15:12
von __blackjack__
@mjleonir: Was bedeutet `lang`? Und warum gibt es kein `kurz`? Spass beiseite: Gewöhne dir am besten gar nicht erst an kryptische Abkürzungen für Namen zu verwenden. Wenn `language` gemeint ist, dann schreib auch `language`.
Zudem wäre `lang_input` eigentlich `language` und `lang` wäre `language_filename`.
„Column“ bedeutet auf Deutsch „Spalte“, die Kommentare sind also etwas verwirrend wenn man eigentlich „Zeile“ meint.
Zeichenketten und Werte mit ``+`` zusammenstückeln ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit `format()` oder ab Python 3.6 auch f-Zeichenkettenliterale.
Beim öffnen von Textdateien sollte man immer die Kodierung explizit angeben.
Du kannst die Datei *einmal* einlesen, am besten mit `list()` statt `read()` und `split()`, und dann aus der Liste mit den Zeilen die beiden gewünschten nacheinander per Index auswählen.
Edit:
Code: Alles auswählen
#!/usr/bin/env python3
import os
def main():
language_name = input('Sprache? ')
filename = os.path.join('lang', language_name + '.txt')
with open(filename, 'r', encoding='utf-8') as file:
lines = list(file)
print(lines[9], end='')
print(lines[6], end='')
if __name__ == '__main__':
main()
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 15:19
von mjleonir
__blackjack__ hat geschrieben: Donnerstag 18. April 2019, 15:12
@mjleonir: Was bedeutet `lang`? Und warum gibt es kein `kurz`? Spass beiseite: Gewöhne dir am besten gar nicht erst an kryptische Abkürzungen für Namen zu verwenden. Wenn `language` gemeint ist, dann schreib auch `language`.
„Column“ bedeutet auf Deutsch „Spalte“, die Kommentare sind also etwas verwirrend wenn man eigentlich „Zeile“ meint.
Zeichenketten und Werte mit ``+`` zusammenstückeln ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit `format()` oder ab Python 3.6 auch f-Zeichenkettenliterale.
Beim öffnen von Textdateien sollte man immer die Kodierung explizit angeben.
Du kannst die Datei *einmal* einlesen, am besten mit `list()` statt `read()` und `split()`, und dann aus der Liste mit den Zeilen die beiden gewünschten nacheinander per Index auswählen.
Danke für die ganze Kritik

. Was ich mir bei column gedacht habe, weiß ich auch nicht, war spät ^^.
Bin ein großer fan von kryptischen Abkürzungen

. Aber ich versuche es verständlicher zu gestalten.
Und ja, ich habe vor Jahren mich mit SmallBASIC an das Programmieren rangetastet, vielleicht kommt es daher, dass ich das alles so zusammenstückele.
Ein Freund wollte mit mir zusammen etwas programmieren weshalb ich endlich den anreiz hatte etwas neues zu lernen.
Danke auch für den Vorschlag mit `list()`, werde ich nun probieren.
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 15:31
von mjleonir
Code: Alles auswählen
import os
def main():
language_name = input('Sprache? ')
filename = os.path.join('lang', language_name + '.txt')
if not os.path.exists(filename):
print('This language is not supported')
main()
with open(filename, 'r') as file:
lines = list(file)
print(lines[9], end='\n')
print(lines[6], end='\n')
if __name__ == '__main__':
main()
Habe den Code nun etwas abgeändert, vielen Dank nochmal, ich glaube das hat mein Problem gelöst

.
Habe durch 'import os' noch eine Abfrage eingefügt, ob die Sprache überhaupt existiert.
Das utf-8 encoding habe ich entfernt, da ich dadurch nur 'en' aufrufen konnte, nicht 'de'.
MfG
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 15:38
von __deets__
Hmja. Du scheinst wirklich noch sehr in BASIC zu stecken. Funktionen sind keine Sprungmarken wie GOTO in BASIC. Durch deinen simplen Aufruf von main() im Fehlerfall hast du jetzt eine Rekursion erzeugt. Das hat zwei Effekte: erstens geht dann irgendwann der Stack aus (ok, das sind ein paar tausend Aufrufe, aber trotzdem). Vor allem aber wird nach erfolgreichem durchlaufen von main einfach wieder zurueckgekehrt an die Stelle, wo du im Fehlerfall verzweigt bist. Und dann versucht, mit einem nicht-existierenden Pfad weiter zu machen. Probier es mal aus.
Stattdessen kannst du hier zB eine while-Schleife machen, die du erst dann verlaesst (mit break), wenn du eine existierende Datei angegeben hast.
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 16:18
von mjleonir
Code: Alles auswählen
def main():
language_name = input('Language? ')
filename = os.path.join('lang', language_name + '.txt')
while not os.path.exists(filename):
print('This language is not supported.')
language_name = input('Language? ')
filename = os.path.join('lang', language_name + '.txt')
if os.path.exists(filename):
break
Das wäre jetzt mein Ansatz für einen while-loop. Ist das zu kompliziert gemacht, oder passt das so?
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 16:24
von __deets__
Die Dopplung der Variablen ist natuerlich nicht so schoen. Da nimmt man einfach eine while-True-Schleife und verlaesst die dann. Und dann das ganze auch noch in eine Funktion gepackt, so das die main einfacher wird.
Code: Alles auswählen
def get_language_filename():
while True:
language = input("Language?")
full_path = os.path.join(...)
if os.path.exists(full_path):
return full_path
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 16:26
von mjleonir
Ja, ist mir auch aufgefallen, muss noch viel lernen wie man sowas löst

. Deswegen bin ich ja hier.
Danke.
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 16:40
von __blackjack__
@mjleonir: Wenn UTF-8 falsch ist, dann musst Du da die tatsächliche Kodierung verwenden. Einfach weglassen geht nicht. Denn dann würde ich zum Beispiel Probleme mit Deinen deutschsprachigen Dateien bekommen, da bei mir standardmässig UTF-8 verwendet wird wenn ich keine Kodierung angebe.
Wobei es wahrscheinlich sinnvoll wäre wenn Du Deine Textdateien genau wie Python-Quelltexte auch UTF-8 kodiert speicherst.
Statt die Existenz der Datei vorher zu prüfen, würde man in Python eher auf die Ausnahme entsprechend reagieren. Denn zwischen Prüfung und Öffnen der Datei kann sie ja gelöscht werden, und es gibt auch noch andere Gründe warum eine Datei nicht geöffnet werden kann. Zugriffsrechte beispielsweise, oder unter Windows auch beliebt das die Datei schon von einem anderen Prozess geöffnet ist.
Wenn am Ende von der `print()`-Ausgabe ein Zeilenende-Zeichen ausgegeben werden soll, dann braucht man `end` nicht angeben – das ist schon die Voreinstellung.
Code: Alles auswählen
#!/usr/bin/env python3
import os
ENCODING = 'UTF-8'
def main():
while True:
language_name = input('Language? ')
filename = os.path.join('lang', language_name + '.txt')
try:
with open(filename, 'r', encoding=ENCODING) as file:
lines = list(file)
except OSError:
print('This language is not supported!')
except UnicodeDecodeError:
print(
f'The language file {filename!r} is not {ENCODING} encoded'
f' or corrupt!'
)
else:
break
print(lines[9])
print(lines[6])
if __name__ == '__main__':
main()
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 16:51
von mjleonir
__blackjack__ hat geschrieben: Donnerstag 18. April 2019, 16:40
@mjleonir: Wenn UTF-8 falsch ist, dann musst Du da die tatsächliche Kodierung verwenden. Einfach weglassen geht nicht. Denn dann würde ich zum Beispiel Probleme mit Deinen deutschsprachigen Dateien bekommen, da bei mir standardmässig UTF-8 verwendet wird wenn ich keine Kodierung angebe.
Habe nun beide Dateien noch einmal als UTF-8 gespeichert, beide waren vorher ANSI. Trotzdem hat die eine geklappt die andere nicht... Nun klappen aber beide.
__blackjack__ hat geschrieben: Donnerstag 18. April 2019, 16:40
Wenn am Ende von der `print()`-Ausgabe ein Zeilenende-Zeichen ausgegeben werden soll, dann braucht man `end` nicht angeben – das ist schon die Voreinstellung.
Ist mit dem jetzigem Code von dir auch nicht mehr nötig.. Vorhin hat er dann alles in der selben Zeile ausgegeben, weswegen ich das noch dazugemacht habe.
Danke trotzdem.
Lerne durch diesen einen Thread immer mehr ^^
MfG
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 19:11
von mjleonir
Ich habe nun etwas zum Code ergänzt:
Code: Alles auswählen
import os
ENCODING = 'UTF-8'
def main():
while True:
language_name = input('Language? ')
filename = os.path.join('lang', language_name + '.txt')
try:
with open(filename, 'r', encoding=ENCODING) as file:
lines = list(file)
except OSError:
print('This language is not supported!')
except UnicodeDecodeError:
print(
f'The language file {filename} is not {ENCODING} encoded'
f' or corrupt!'
)
if language_name == 'ls':
for line_number in lines:
print(line_number)
else:
break
Mit dem letzten if-statement (if language_name == 'ls') sollen alle Zeilen der Datei 'ls' ausgegeben werden.
Das funktioniert soweit auch, jedoch bleibt zwischen jeder Zeile eine weitere frei, was mich etwas stört.
Wie kann man das beheben?

Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 19:26
von mjleonir
Hab es nun folgendermaßen gelöst:
Code: Alles auswählen
import sys
if language_name == 'ls':
for line_number in lines:
sys.stdout.write(line_number)
also sys.stdout.write() anstatt print().
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 19:39
von __blackjack__
@mjleonir: Das war ja der Grund warum ich ``end=''`` bei `print()` gesetzt hatte. `line_number` ist als Name falsch. Das ist ja keine Zeilennummer sondern die Zeile selbst.
Und der Code ist falsch strukturiert: Immer wenn man etwas anderes als 'ls' als Namen eingibt wird die ``while``-Schleife verlassen. Auch wenn die Datei gar nicht geladen werden konnte. Dann ist aber `lines` undefiniert. Wenn man 'ls' eingibt, dann müsste ja vorher eine Sprachdatei erfolgreich geladen worden sein, was aber zum Abbruch der Schleife geführt hätte (es sei denn die Sprachdatei hiess ``lang/ls.txt``), womit man dann aber keine Chance mehr hat 'ls' einzugeben.
Das bei ``end=''`` beim `print()` beide Zeilen (9 und 6) in einer Zeile ausgegeben wurden, kann übrigens nur passieren wenn 9 die letzte Zeile in der Datei ist und die Zeile nicht mit einem Zeilenende-Zeichen abgeschlossen war. Zumindest unter Linux/Unix würde ich das als fehlerhafte Datei ansehen, denn das kann bei so einigen Werkzeugen die Textdateien verarbeiten zu Problemen führen.
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 20:06
von mjleonir
__blackjack__ hat geschrieben: Donnerstag 18. April 2019, 19:39
@mjleonir: Das war ja der Grund warum ich ``end=''`` bei `print()` gesetzt hatte. `line_number` ist als Name falsch. Das ist ja keine Zeilennummer sondern die Zeile selbst.
Und der Code ist falsch strukturiert: Immer wenn man etwas anderes als 'ls' als Namen eingibt wird die ``while``-Schleife verlassen. Auch wenn die Datei gar nicht geladen werden konnte. Dann ist aber `lines` undefiniert. Wenn man 'ls' eingibt, dann müsste ja vorher eine Sprachdatei erfolgreich geladen worden sein, was aber zum Abbruch der Schleife geführt hätte (es sei denn die Sprachdatei hiess ``lang/ls.txt``), womit man dann aber keine Chance mehr hat 'ls' einzugeben.
Das bei ``end=''`` beim `print()` beide Zeilen (9 und 6) in einer Zeile ausgegeben wurden, kann übrigens nur passieren wenn 9 die letzte Zeile in der Datei ist und die Zeile nicht mit einem Zeilenende-Zeichen abgeschlossen war. Zumindest unter Linux/Unix würde ich das als fehlerhafte Datei ansehen, denn das kann bei so einigen Werkzeugen die Textdateien verarbeiten zu Problemen führen.
Über die Benennungen sehe ich vorerst hinweg, geht mir erstmal um den Code selbst.
ls.txt ist auch als Sprachdatei festgelegt, auch wenn das so etwas gepfuscht und falsch ist, da diese Datei am Ende ausgibt welche Sprachen es alles gibt.
Das ganze ist in den while-loop eingebaut. Wenn man nach der Sprache gefragt wird kann man auch "ls" eingeben und einem werden alle verfügbaren Sprachen angezeigt.
Dann ist man weiterhin im loop und kann nun eine Sprache eingeben oder noch einmal "ls" wenn man Lust hat.
Ja, das kann sein, dass die letzte Zeile nicht mit einem Zeilenumbruch beendet wurde aber nun haben wir ja kein ``end=''`` mehr im code, weswegen ich zu der Lösung gegriffen habe.
Ganz falsch ist es ja nicht, oder? Bis auf die Benennung von `line_number`.
Re: Datei auslesen
Verfasst: Donnerstag 18. April 2019, 21:18
von __blackjack__
@mjleonir: Benennung ist wichtig! Falsche Benennung kann Leser verwirren, inklusive den Autor selber, denn man liest Quelltext öfter als man ihn schreibt. Und wenn einem kein passender Name einfällt, ist das oft auch ein Zeichen das etwas nicht stimmt. Entweder hat man das Problem/die Lösung selbst nicht ganz verstanden, oder man versucht Daten in Objekten zusammen zu fassen, die nicht zusammen gehören.
Der Code wird problematisch wenn ``ls.txt`` nicht existiert oder nicht gelesen werden kann. Ausserdem muss der Inhalt der ``ls.txt``-Datei nicht mit den tatsächlich vorhandenen Sprachen übereinstimmen. Ich würde da ja eher direkt nach der Eingabe des Benutzers prüfen ob er eine Sprache laden oder sich die Vorhandenen auflisten lassen möchte, und die dann anhand der *.txt-Dateien im ``lang/``-Verzeichnis auflisten lassen. Statt `os.path` könnte man sich in dem Zusammenhang auch mal mit dem `pathlib`-Modul auseinander setzen.