Python fügt überflüssige Leerzeilen hinzu

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
user1370514405
User
Beiträge: 5
Registriert: Donnerstag 6. Juni 2013, 11:27

Hi,
ich lese mit folgendem Code eine Datei ein und speichere die Zeilen in einer Liste:

Code: Alles auswählen

with open ("dateiname.xml") as xml:
	liste = xml.readlines()
Wenn ich diese Liste dann ausgebe, ist hinter jeder Zeile noch eine zusätzliche Leerzeile:

Code: Alles auswählen

for line in liste:
	print line
Woher kommt das und wie werde ich es los? :K
BlackJack

@user1370514405: Die Zeilen aus der Datei haben am Ende ein Zeilenende-Zeichen und ``print`` gibt am Ende auch noch einmal ein Zeilenende-Zeichen aus. Loswerden könntest Du es in dem Du es von den Elementen in der Liste entfernst. Schau Dir mal an was Zeichenketten so alles an nützlichen Methoden haben. Oder Du gibst die Zeilen nicht per ``print`` aus, sondern schreibst sie zum Beispiel direkt mit `sys.stdout.writelines()` auf die Standardausgabe.

Edit: Nur so wegen der Namen: Dir ist klar das man XML-Dateien nicht wie Textdateien verarbeiten sollte, sondern einen XML-Parser verwenden sollte wenn man tatsächlich etwas mit dem Inhalt der Datei anfangen möchte!?
user1370514405
User
Beiträge: 5
Registriert: Donnerstag 6. Juni 2013, 11:27

Super, funktioniert! Danke.
BlackJack hat geschrieben:Nur so wegen der Namen: Dir ist klar das man XML-Dateien nicht wie Textdateien verarbeiten sollte, sondern einen XML-Parser verwenden sollte wenn man tatsächlich etwas mit dem Inhalt der Datei anfangen möchte!?
Ich bin ein ziemlicher Anfänger und das ist mir nicht klar, nein. Ich weiß was ein Parser ist, aber nicht warum ich ihn hier verwenden sollte.

Was das ganze Programm machen soll:

Ich lese Zeilen aus einer Datei ein und füge diese mit Hilfe von regulären Ausdrücken an bestimmten Stellen in eine XML-Datei ein.
BlackJack

@user1370514405: Genau so etwas sollte man mit XML nicht machen. XML ist ziemlich „zerbrechlich”, d.h. man kann das ganz schnell mal kaputt machen und hat dann eine Datei die kein gültiges XML mehr ist und damit auch von keinem Programm welches XML erwartet mehr verarbeitet werden kann. Es ist auch schwierig reguläre Ausdrücke zu schreiben die jedes denkbare gültige XML erkennen. Wenn man XML-Dateien wie Textdateien behandelt schreibt man früher oder später kaputtes XML oder erkennt etwas nicht mehr weil sich die Form der Serialisierung aus irgendwelchen Gründen geändert hat. Beides kann man umgehen wenn man das Parsen und Serialisieren einer XML-Bibliothek überlässt. In der Standardbibliothek von Python gibt es das `ElementTree`-Modul dafür. Das externe Modul/Paket `lxml` bietet die gleiche API allerdings mit einigen interessanten Erweiterungen wie zum Beispiel XPath oder CSS-Selektion.
Benutzeravatar
Kebap
User
Beiträge: 786
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

user1370514405 hat geschrieben: Ich bin ein ziemlicher Anfänger und das ist mir nicht klar, nein. Ich weiß was ein Parser ist, aber nicht warum ich ihn hier verwenden sollte.
Damit du einfach dem Parser sagen kannst "Gib mir mal Info x von Ort y" und dich nicht selbst mit der Programmierung des Parsens herumschlagen musst. ;)
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.
user1370514405
User
Beiträge: 5
Registriert: Donnerstag 6. Juni 2013, 11:27

Bevor ich die Zeilen aus der Quell-Datei einfüge, muss ich sie verändern (einige Bereiche werden entfernt). Das mache ich so:

Code: Alles auswählen

# Datei einlesen und in Liste speichern
with open("file.txt") as txt:
	source = txt.readlines()

# Zeilen verändern
for line in source:
	line = re.sub(pattern, '', line)
Wenn ich nun in der Schleife

Code: Alles auswählen

sys.stdout.writelines(line)
ausführe, werden die Veränderungen richtig angezeigt. Wenn ich aber eine neue Schleife mache

Code: Alles auswählen

for line in source:
	sys.stdout.writelines(line)
sind die Veränderungen weg. Kann mir jemand sagen warum?
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Wert geänderter Variablen wandert nicht auf magische Weise an seinen Ursprung zurück:

Code: Alles auswählen

>>> data = [1,2,3]
>>> for a in data:
...     a = a**2
...     print a
...
1
4
9
>>> print data
[1, 2, 3]
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

... das gilt aber leider nur für "immutable" Datentypen, wie Integer und Strings, Listen verhalten sich anders:

Code: Alles auswählen

>>> data = [[1], [2], [3]]
>>> for a in data:
...     a[0] = a[0]**2
...     print a
...
[1]
[4]
[9]
>>> print data
[[1], [4], [9]]

Das ist nicht ganz leicht zu verstehen, wenn man nicht weiss womit man's zu tun hat, eine Erklärung gibt's hier:
http://docs.python.org/2/reference/datamodel.html
BlackJack

@user1370514405: Deine letzte Schleife ist sehr ineffizient! Du gehst in einer ``for``-Schleife über die Zeilen, und gibst dann jede einzelne Zeile mit der `writelines()`-Methode aus, was dazu führt das jedes Byte einzeln ausgegeben wird. Entweder verwendest Du dort nur `write()` oder lässt die ``for``-Schleife weg und übergibst `writelines()` die Liste mit den Zeilen.

@mcdwerner: Das gilt für alle Datentypen, auch für Listen. Es ist ein Unterschied ob man einen Namen neu bindet, oder ein Objekt *verändert*.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

@BlackJack:
Es ist ein Unterschied ob man einen Namen neu bindet, oder ein Objekt *verändert*.
Das ist ja gerade das verwirrende, es gibt eben *unveränderbare* Objekte, wie Integer und Strings. Und wenn ich von diesen einen anderen Wert benötige (errechnet habe, wie auch immer...) dann verweise ich auf ein anderes Objekt, mit einem anderen Wert.
Bei einem *veränderbaren* Objekt verweise ich auf das selbe Objekt, das wiederum auf einen anderen Wert verweist.
Wenn ich so drüber nachdenke: bedeutet das ja, dass jedes veränderliche Objekt letztendlich irgendwann auf einen unveränderbaren Wert verweisen muss? Das war mir so bis jetzt nicht bewusst, ist aber logisch oder verknotet sich gerade wieder mein Gehirn?
user1370514405
User
Beiträge: 5
Registriert: Donnerstag 6. Juni 2013, 11:27

Code: Alles auswählen

for place, line in enumerate(source):
	line = re.sub(pattern, '', line)
	source[place] = line
Damit hat es funktioniert, falls sonst noch jemand das Problem hat. Danke an alle.
BlackJack

@user1370514405: Das ist eine für Python sehr unübliche Lösung. Man würde einfach eine neue Liste mit den geänderten Werten erstellen. Oder einen Generatorausdruck, damit die Daten erst dann erzeugt werden, wenn man sie benötigt.

Code: Alles auswählen

    a_re = re.compile(pattern)
    modified_lines = (a_re.sub('', line) for line in source)
user1370514405
User
Beiträge: 5
Registriert: Donnerstag 6. Juni 2013, 11:27

BlackJack hat geschrieben:Das ist eine für Python sehr unübliche Lösung.
Ich werde in Zukunft wohl auch lieber mit PERL arbeiten. :mrgreen:
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Du würdest also damit dem Stereotyp des Perl-Programmierers entsprechen der sämtliche seiner Probleme auf mehr oder weniger kryptische Art mit Regex löst.
BlackJack

@user1370514405: Wenn Dir die Sprache eher liegt, dann mach das. Ich bin von Perl unter anderem damals weg weil das dort mit den Namen und was sie bedeuten *komplizierter* ist als in Python. In Perl muss man immer darauf achten in welchem Kontext und mit welchen Sigils man einen Namen benutzt um zu wissen zu welchem Wert er ausgewertet wird, beziehungsweise worauf eine Zuweisung Auswirkungen hat. Also zu Beispiel ob die Zuweisung ``$name = 42`` nur den Namen an den Wert bindet oder ob ``$name`` eigentlich ein Alias für eine andere Stelle im Speicher ist und dort, zum Beispiel in einem Array, den Wert verändert. In Python bedeutet so eine Zuweisung wie ``name = 42`` immer das der Name an den Wert gebunden wird.
Antworten