Seite 1 von 1
Wort Suchen
Verfasst: Freitag 2. November 2012, 13:29
von Evilsadness
Hayyy,
vorweg, ich bin neu hier und ein blutiger Anfänger in Python!! Ich beschäftige mich seit 1 Monat ca. damit.
Also mein Problem ist wie folgt:
Ich sollte zuerst mit Python ein Programm schreiben, dass automatisch ein Kassenbon(Quittung) in eine Xml-Datei schreibt.
Damit hatte ich kein Problem! Nun kommt folgende "zusatzaufgabe". Ich soll ein neues Programm schreiben, das die Datei "einliest" und überprüft um das Gesamtergebnis stimmt und lediglich die einzige Ausgabe soll sein, ob es stimmt oder nicht.
Folgende Xml-Datei entsteht aus dem ersten Programm:
Code: Alles auswählen
<?xml version='1.0' encoding='UTF-8'?>
<Kassenbon>
<Position nummer = "1">
<Artikel>Duschgel</Artikel>
<Preis>1.99 Euro </Preis>
<Menge>1</Menge>
<Summe>1.99 Euro </Summe>
</Position>
<Position nummer = "2">
<Artikel>Zahnpasta</Artikel>
<Preis>1.49 Euro </Preis>
<Menge>1</Menge>
<Summe>1.49 Euro </Summe>
</Position>
<Position nummer = "3">
<Artikel>Milch</Artikel>
<Preis>0.45 Euro </Preis>
<Menge>2</Menge>
<Summe>0.9 Euro </Summe>
</Position>
<Position nummer = "4">
<Artikel>Milka</Artikel>
<Preis>0.79 Euro </Preis>
<Menge>1</Menge>
<Summe>0.79 Euro </Summe>
</Position>
<Position nummer = "5">
<Artikel>Orangensaft</Artikel>
<Preis>1.19 Euro </Preis>
<Menge>3</Menge>
<Summe>3.57 Euro </Summe>
</Position>
<Gesamtpreis>8.74 Euro </Gesamtpreis>
</Kassenbon>
(Hier wird die Datei leider nicht "wohlgeformt" angezeigt.)
Ich muss also die Datei einlesen:
ich weiß nicht wie ich nun von jeden Artiel die "Summe" addieren kann bzw. ich weiß nicht wie ich ein genau bestimmten Wert(String oder int) aus der Datei lesen kann und den in einer Variabel abespeichern kann.
Für viele bestimmt einfach und schnell gemacht, für mich aber nicht.
Ich weiß nicht welche Methoden ich benutzen soll.
Wenn Ihr eine Methode benutzt, dann macht bitte immer ein Kommentar dazu, was die Methode macht!!
Vielen Dank im Vorraus !!!
Ach dabei soll im neuen Programm ganz am Anfang " Gesamtpreis = 0" gesetzt werden!
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 13:42
von Sirius3
Hallo Evilsadness,
zum Lesen und Schreiben von xml hat sich unter Python elementtree bewährt.
Code: Alles auswählen
import xml.etree.ElementTree as ET
bon=ET.ElementTree(file='kassenbon.xml')
Die Methoden find und findall helfen dann beim Durchsuchen der xml-Struktur.
Grüße
Sirius
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 14:03
von Evilsadness
So meinte ich das nicht.
Ich soll kein Module implemtieren.
Ich suche irgenwelche Methoden, die z.B. beim Duschgel den Preis rauslesen kann , also irgendwie in der Zeile gehen und dann vllt. mit der splitt Methode die Zeile trennen oder so in der Art. Und dies mit jedem Produkt machen und die Preise Addieren und gucken ob es mit dem Gesamtergenis übereinstimmt.
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 14:21
von sparrow
Verstehe ich das richtig? Du darfst keine Module verwenden? Das klingt aber seltsam.
Nunja, womit hast du denn genau Schwierigkeiten? Wie man Dateien öffnet weißt du, sonst hättest du die Datei nicht speichern können, nehme ich an.
Wenn du da selbst parsen willst, dann helfen die die
Methoden für Zeichenketten mit dem Inhalt umzugehen. Damit kann man in Zeichenketten suchen und so auch lesen.
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 14:58
von Evilsadness
ich darf schon mit Modulen arbeiten, jedoch sollten wir es ohne versuchen.
Super seite!!! Nach sowas habe ich gesucht!
Gibt es vllt. Lösungsvorschläge?
Versuche mich morgen mittag nochmal ran, jetzt habe ich leider keine Zeit mehr dafür.
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 17:02
von BlackJack
@Evilsadness: XML sollte man ohne eine vernünftige XML-Bibliothek weder schreiben noch lesen. Das ist kein einfaches Textformat, auch wenn es auf den ersten Blick so aussehen mag.
Man kann sehr leicht beim Schreiben Fehler machen, so dass die Datei von keinem anderen Programm, welches XML erwartet, mehr gelesen werden kann.
Andersherum ist es sehr aufwändig selbst Code zu schreiben, der wirklich XML lesen und verarbeiten kann und nicht nur eine Untermenge von wohlgeformten XML.
Es gibt aber einfach zu verwendende Bibliotheken, die wohlgeformtes XML erzeugen und lesen können. Es macht also wenig Sinn darauf zu verzichten und stattdessen das Rad neu zu erfinden, nur dass es zwangsläufig ein kaputtes, eckiges Rad sein wird.
Lesehinweis: Mindestens der Abschnitt „Don’t think of XML as a text format” in
HOWTO Avoid Being Called a Bozo When Producing XML.
Wenn Dein Programm XML lesen können soll, musst Du auch immer damit rechnen, dass die Datei durch irgendein XML-Werkzeug bearbeitet wurde und in den Grenzen der XML-Spezifikation anders gespeichert sein kann, ohne dabei vom Inhalt her verändert worden zu sein. Die Zeichenkodierung kann verändert werden, einzelne (Sonder)zeichen können als Character-Entitäten serialisiert werden, Text kann teilweise in CDATA-Blöcke eingwfasst sein, „whitespace” kann verändert worden sein, Kommentare können hinzugefügt oder gelöscht worden sein, und so weiter.
Falls Du beim XML-Beispiel keinen Code-Block im Beitrag verwendet hast, wäre er übrigens weiterhin wohlgeformt dargestellt worden! Solange es kein Schema für den Kassenbon gibt, der „whitespace” in Textknoten als signifikant deklariert wäre es sogar zusätzlich auch valides XML alles in einer Zeile zu schreiben oder innerhalb von „whitespace” Umbrüche zu machen.
Das Kassenbon-Format selber hat das Problem, dass die Geldbeträge nicht nur die Zahl, sondern auch die Währung enthalten. Das ist ungünstig, weil es unnötige Arbeit beim Verarbeiten verursacht. Man hätte auch mehr über Attribute repräsentieren können. Und die Währung pro Position oder gar für den gesamten Kassenbon angeben können. So ist das ziemlich redundant und sieht eher wie ein Dokument zur einfachen Darstellung als eines zum weiterarbeiten mit den Daten aus.
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 18:35
von StefanLawl
Nunja, ich weiß nicht ob du das meinst, aber ich wenn du keine Module importieren darfst (/willst), würde ich die Datei eventuell so auslesen:
Code: Alles auswählen
datei = open("bon.xml", "r")
for line in datei:
print line
Würdest du jetzt alle Preise ausgeben wollen, ginge das z.B. so:
Code: Alles auswählen
datei = open("bon.xml", "r")
preise=[]
for line in datei:
if 'Preis' in line:
preise.append(line[13:17])
print preise
Das Problem dabei ist aber, dass du nicht anständig damit arbeiten kannst, da es speziell nur für diese Datei verwendbar ist ( und es ist einfach nicht "schön"

) Bin selbst noch neu mit Python, ich hoffe das konnte dir trotzdem auf irgendeine Weise helfen.
Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 19:37
von Hyperion
StefanLawl hat geschrieben:Nunja, ich weiß nicht ob du das meinst, aber ich wenn du keine Module importieren darfst (/willst), würde ich die Datei eventuell so auslesen:
Code: Alles auswählen
datei = open("bon.xml", "r")
for line in datei:
print line
Und ich poste es zum wiederholten Male (

)unter Deine ``open``-Konstrukte: Dateien sollte man immer mittels ``with`` öffnen!
Code: Alles auswählen
with open(...) as handler:
for line in handler:
print line
Das ist wesentlich sicherer, da die Datei in jedem Falle geschlossen wird - also auch beim Auftreten einer Exception. Zudem spart man sich das explizite ``handler.close()`` und vergisst das Schließen damit nicht; so wie Du gerade eben
@Evilsadness: In welchem Kontext müsst ihr das denn lösen? Ich würde mal behaupten, dass man an einer Uni jeden Assistenten / Hiwi dazu bekommt, einem die Übung abzunehmen, wenn man mit stichhaltigen Argumenten kommt! Und das Schreiben eines eigenen XML-Parsers / -Generators ist ja wohl eher nicht Sinn eurer Aufgabe, sondern das Lernen von Grundlagen. Damit reduziert es sich auf das elementare Verständnis von gängigen Datenstrukturen und der Möglichkeiten, Funktionen richtig zu kombinieren. Das Benutzen einer fremden Bibliothek spricht imho eher dafür, dass man dieses Verständnis erworben hat, denn das (schlechte) Implementieren eines eigenen XML-Parsers mit den üblichen, schon zig Mal in Übungen durchgekauten Funktionen und Methoden...
An der Schule sieht es da evtl. ein wenig düsterer aus, da Du selber diese Argumentation gegenüber Deinem Lehrer vortragen müsstest... das kann je nach Alter auch in Sachen Selbstbewusstsein schwierig sein
Eines kannst Du aber immer machen: Demjenigen dieses Forum nennen, dann kann er sich ja mit uns "anlegen" und über diese wenig sinnvollen Anforderungen diskutieren

Re: Wort Suchen
Verfasst: Freitag 2. November 2012, 22:59
von BlackJack
Parsen und erzeugen von solchen Kassenbon-XML-Dokumenten mit einer ordentlichen XML-Bibliothek, die gültiges XML erzeugt und auch jeden Kassenbon in gültigem XML lesen kann:
Code: Alles auswählen
#!/usr/bin/env python
from decimal import Decimal
try:
from lxml import etree
except ImportError:
import xml.etree.ElementTree as etree
class ReceiptError(Exception):
pass
class Amount(object):
def __init__(self, value, currency):
self.value = value
self.currency = currency
def __str__(self):
return '%s %s' % (self.value, self.currency)
def __eq__(self, other):
return (self.value, self.currency) == (other.value, other.currency)
def __ne__(self, other):
return not (self == other)
def __add__(self, other):
if self.currency != other.currency:
raise ValueError('currency mismatch')
return Amount(self.value + other.value, self.currency)
def __radd__(self, other):
return self if other == 0 else NotImplemented
def __mul__(self, other):
return Amount(self.value * other, self.currency)
@classmethod
def from_string(cls, string):
amount, currency = string.split(None, 1)
return cls(Decimal(amount), currency.strip())
class Position(object):
TAG = 'Position'
DESCRIPTION_TAG = 'Artikel'
PRICE_TAG = 'Preis'
COUNT_TAG = 'Menge'
TOTAL_TAG = 'Summe'
NUMBER_ATTRIBUTE = 'nummer'
def __init__(self, description, price, count=1):
self.description = description
self.price = price
self.count = count
def __str__(self):
return '%15s %3d x %s = %s' % (
self.description, self.count, self.price, self.total
)
@property
def total(self):
return self.price * self.count
def as_xml(self, number):
result = etree.Element(self.TAG, {self.NUMBER_ATTRIBUTE: str(number)})
for tag, value in [
(self.DESCRIPTION_TAG, self.description),
(self.PRICE_TAG, self.price),
(self.COUNT_TAG, self.count),
(self.TOTAL_TAG, self.total),
]:
node = etree.SubElement(result, tag)
node.text = unicode(value)
return result
@classmethod
def from_xml(cls, node, expected_number=None):
if expected_number is not None:
number = int(node.get(cls.NUMBER_ATTRIBUTE))
if number != expected_number:
raise ReceiptError(
'expected number %d, got %d' % (expected_number, number)
)
result = Position(
node.find(cls.DESCRIPTION_TAG).text,
Amount.from_string(node.find(cls.PRICE_TAG).text),
int(node.find(cls.COUNT_TAG).text)
)
if result.total != Amount.from_string(node.find(cls.TOTAL_TAG).text):
raise ReceiptError(
'total at position %d is incorrect' % expected_number
)
return result
class Receipt(object):
TAG = 'Kassenbon'
TOTAL_TAG = 'Gesamtpreis'
def __init__(self):
self.positions = list()
def __str__(self):
result = ['%d. %s' % (i, p) for i, p in enumerate(self, 1)]
result.append('Total: %s' % self.total)
return '\n'.join(result)
def __len__(self):
return len(self.positions)
def __iter__(self):
return iter(self.positions)
@property
def total(self):
return sum(position.total for position in self)
def add(self, position):
self.positions.append(position)
def as_xml(self):
result = etree.Element(self.TAG)
for number, position in enumerate(self, 1):
result.append(position.as_xml(number))
total_node = etree.SubElement(result, self.TOTAL_TAG)
total_node.text = str(self.total)
return result
@classmethod
def from_xml(cls, node):
result = cls()
for expected_number, position_node in enumerate(
node.findall(Position.TAG), 1
):
result.add(Position.from_xml(position_node, expected_number))
total = Amount.from_string(node.find(cls.TOTAL_TAG).text)
if result.total != total:
raise ReceiptError(
'expected total %s, got %s' % (result.total, total)
)
return result
def main():
receipt_node = etree.parse('test.xml')
try:
receipt = Receipt.from_xml(receipt_node)
except ReceiptError as error:
print 'Error:', error
else:
print receipt
print
etree.dump(receipt.as_xml())
print
if __name__ == '__main__':
main()
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 15:36
von Evilsadness
@ StefanLawl PERFEKTT!!!! Genau nach sowas habe ich gesucht!!! ich weiß es ist ziemlich "sinnlos" mit sowas zuarbeiten, also ein Programm schreiben, für nur "diese" Datei, aber wir sollen halt mit herum versuchen und probieren uns besser in python reinarbeiten!
Habe es nun Fertig und sieht wie folgt aus:
Code: Alles auswählen
datei = open("bon.xml", "r")
preise=[]
gesamtpreis =""
for line in datei:
if "Summe" in line:
preise.append(line[9:13])
if "Gesamtpreis" in line:
gesamtpreis = line[14:18]
print ("Einzelne Preise: " + str(preise))
print ("Gesamtpreis in der Datei: " + gesamtpreis + " Euro")
i= len(preise)
Gesamtpreis = 0
for i in range(0,i,1):
Gesamtpreis = Gesamtpreis + float(preise[i])
print ("Der Gesamtpreis der vom Programm ausgerechnet wurden ist: " + str(Gesamtpreis)+"\n\n")
if str(Gesamtpreis) == gesamtpreis:
print ("Die Preise Stimmen über ein!!")
else:
print("Leider stimmen die Preise nicht überein!")
Vieeelen Dank!!!!!!!!!!!
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 16:11
von Sirius3
Hallo Evilsadness,
ein paar Anmerkungen:
datei wird nicht mehr geschlossen. Die einfachste und sicherste Möglichkeit ist
ein with-Block um die ganze Einleseschleife:
Dein line[9:13] funktionier spätestens bei Preisen ab 10€ nicht mehr.
Ein line[line.index('<Summe>')+7:line.index('Euro')] ist wohl das mindeste.
Eine for-Schleife in Python iteriert immer über Listen oder ähnliches.
Der Umweg über range ist unsinnig.
oder kürzer:
Die Abfrage, ob str(Gesamtpreis)==gesamtpreis ist, wird nicht immer funktionieren.
Irgendwann gibt es Rundungsfehler und aus 4.25 wird 4.2499999999998.
Grüße
Sirius
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 18:19
von StefanLawl
Wäre besser:
Wobei Sirius' Lösung wohl am besten wäre
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 19:04
von Evilsadness
Abend Serius3,
Verbesserungen nehme ich geeerrnnen auf!!! Vielen dank!!!
aber habe noch paar Fragen:
1:
ich kann doch anstatt
die datei am ende schließen.. ich hatte es leider bei mir vergessen.
also am ende noch
2:
also nach dem ":" line.index(' Euro') ist es ja verständlich, dass man bis " Euro" Zeile geht,
jedoch wieso am anfang line.index('<Summe>')+7 ?!?! ist doch einfacher wenn man das so schreibt:
Weil der tag "('<Summe>')" ändert sich eh nicht, also kann ich ja in zeile 9 anfangen.
3:
sum() = "summiert die Werte in den klammern" --- oder?
map() =???
4:
was ist xrange?
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 19:22
von pillmuncher
@Evilsadness": Das Äquivalent zu
ist nicht
sondern
Code: Alles auswählen
datei = open("bon.xml", "r")
try:
...
finally:
datei.close()
Gerade um solche Konstrukte unnötig zu machen gibt es ja das with Statement.
Re: Wort Suchen
Verfasst: Samstag 3. November 2012, 19:40
von Sirius3
Hallo,
genau wegen der Aussage: Ändert sich eh nicht, schreibst Du
weil Du Dir immer sicher bist dass vor Summe genau 2 Leerzeichen stehen??
Es ist einfach guter Programmierstil keine festen Zahlen zu verwenden, wenn es
möglich ist, die Zahl durch eine beschreibende Operation zu ersetzen.
Irgendwann später ändert sich eine Voraussetzung und dann fragst Du Dich,
was soll die 9 da? Warum funktioniert die Routine jetzt nicht mehr?
2. map wendet die Funktion float auf jedes Element der Liste preise an und erzeugt
daraus eine neue Liste.
Re: Wort Suchen
Verfasst: Sonntag 4. November 2012, 13:34
von Hyperion
Evilsadness hat geschrieben:Abend Serius3,
...
1:
ich kann doch anstatt
die datei am ende schließen.. ich hatte es leider bei mir vergessen.
also am ende noch
Du solltest Dir abgewöhnen, die Kommentare anderer Benutzer zu ignorieren. Ich hatte Dir dazu schon weiter oben etwas geschrieben, Pillmuncher hat es dann noch einmal ausführlicher erklärt, aber im Grunde stand da schon, *wieso* man ``with`` verwenden sollte.
StefanLawl hat geschrieben:
Code:
Wäre besser:
Code:
Das ist im Grunde genommen nur marginal besser und somit genau so schlecht
In Python iteriert man über *Objekte* und nicht über Indizes für Objektzugriffe. Man braucht ganz selten *nur* einen Index. Braucht man Index und Objekt, gibt es die ``enumerate``-Funktion, die einem einen Index zu einem Iterable erzeugt.
Noch einmal deutlich:
Code: Alles auswählen
for i in range(len(data)):
# irgend etwas mit ``data[i]``
Das ist ein absoluter
Anti-Pattern in Python!!! Solchen Code sollte man *nie* schreiben.
EvilSadness hat geschrieben:
3:
Code:
Gesamtpreis = sum(map(float,preise))
Code: Alles auswählen
sum() = "summiert die Werte in den klammern" --- oder?
map() =???
``map`` wendet das im ersten Argument angegebene Callable (hier die Funktion ``float``) jeweils auf alle Elemente der Iterables im zweiten Argument an.
Man kann das auch vielleicht zunächst verständlicher so formulieren:
Oder zunächst als reine List-Comprehension:
Du kannst das aber auch in der Doku nachlesen; ``map`` gehört zu den Built-in Funktionen und sollte daher für Dich schnell zu finden sein
