[Python-de] Programm gesucht

Karl Pflästerer sigurd at 12move.de
Don Apr 1 23:12:16 CEST 2004


On  1 Apr 2004, Werner Warweg <- Werner.Warweg at t-online.de wrote:

> Karl Pflästerer schrieb:

>> Wie sind denn die einzelnen Sätze vonaeinader getrennt? Ich nehme an
>> newline und du hast dies nur in deiner E-Mail wegen der Zeilenlänge so
>> nicht dargestellt?
> Die Sätze sind 80 Byte lang und enden mit carriage-return/line feed
> (CRLF,0d0a)

Das ist gut. Dies machr es einfach, über sie zu iterieren.

[...]
>> z. B. so (du beginnst mit 1 zu zählen):
>             1         2         3         4         5         6 7
>             8
>> 12345678901234567890123456789012345678901234567890123456789012345678901234567890
>  aabbbbbcccccdddddeefggggggggggggggggggggggggggggggggggggggggggggghhhhhhhhhhhiijk

>> und hierunter die Beispielfelder.
> meintest Du das so?
> Dann ist a = Satzart n
>           b = Mandant n
> 	 c = Kontonummer n
>           d = Unterkonto n
[...]
> (a = alpha, n = numerisch)
> weitere Satzarten kann ich später beschreiben. Ich benötige eigentlich
> erst einmal einen Ansatz, wie solch ein Programm anzugehen ist.

Jetzt erst einmal die simpelste Frage: wie liest du die Daten ein und
spaltest sie in die einzelnen Felder auf.

Wenn du eine Textdatei in Python in Python öffnest (mit file()) und sie
zeilenweise einlesen möchtest, geht dies folgendermaßen:

f = file('filename.txt')
for line in f:
    print line
f.close()

Dies würde die Datei zeilenweise auf dem Bildschirm ausgeben.

Um einzelne Abschnitte eines Strings zu erhalten, kann man in Python
eine sogenannte Slice Notation benutzen; du gibst hierzu einen Start-
und Endindex an; die Indexzählung beginnt bei 0. das Ergebnis ist ein
rechtsseitig offenes Intervall (das Ende ist nicht mehr Bestandteil des
Ergebnisses).

Bsp:
>>> s = '0123456789'
>>> s[0:2]
'01'

Für deine Zwecke ist eine kleine Hilfsfunktion ganz praktisch.

def substrings (s, *indice):
    return [s[beg-1:end] for (beg, end) in indice]

Diese Funktion erwartet einen String und beliebig viele Tupel (die
jeweils Start- und Endindex) angeben und liefert eine Liste mit den
entsprechenden Abschnitten zurück.

Ich schrieb oben »beg-1«, damit es für dich bequemer ist; da du von 1 zu
zählen beginnst, muß der Index für Python um 1 erniedrigt werden. Das
Ende muß nicht angepaßt werden, da es ja nicht im Ergebnis erscheint.

Testen wir die Funktion.

>>> s = "aabbbbbcccccdddddeefggggggggggggggggggggggggggggggggggggggggggggghhhhhhhhhhhiijk"
>>> substrings(s, (1,2), (3,7), (8,12), (13,17), (18,19), (20, 20), (21, 65), (66,76), (77,78), (79,79), (80,80))
['aa', 'bbbbb', 'ccccc', 'ddddd', 'ee', 'f', 'ggggggggggggggggggggggggggggggggggggggggggggg', 'hhhhhhhhhhh', 'ii', 'j', 'k']

Scheint zu passen.

Jetzt könnte man entweder über die Indice der Einträge einzelne Felder
herausfischen oder mit Pattermatching (letzeres ist schöner).
Angenommen, du wolltest Mandant und Kontonummer (b und c). Dann kannst
du folgendes schreiben:

>>> mand, ktnr = substrings(s, (3,7), (8,12))
>>> mand
'bbbbb'
>>> ktnr
'ccccc'


Die Variablen mand, ktnr haben also jetzt den Wert, der in dem String an
(3,7) bzw. (8,12) stand.

Das ist im Groben, was du brauchst.

> Ich denke, wenn das Kontenplan "Einlese- und Aufbereitungsprogramm"
> steht         sind die anderen Modifikationen.

Dies kann mit obigem erstellt werden.

> Vorsicht Falle:
> Daten kommen von Groß-EDV (EBCDIC-Code) und Umlaute seltsam:
> RšCKST., das soll RÜCKST. (Rückstellung) heißen
> K™ST              KÖST (Körperschaftssteuer)

Solange die Daten nur gelsen, verglichen und geschrieben werden, sollte
dies kein Problem darstellen.

Was ist nicht weiß: Stehen die Ziffern und der Dezimalpunkt bei
EBCDIC-Code an der gleichen Stelle wie bei ASCII? Wird ein Punkt als
Dezimalzeichen genutzt oder ein Komma? Wenn ein Punkt (der an der
gleichen Stelle wie bei ASCII steht) verwendet wird, ist dies am
einfachsten. Wenn diese Annahmen nicht zutreffen, muß man die Zeichen
eben übersetzen (mit einer Tabelle); dies ist auch nicht wild.

> 148213018430     99998     311003        000108819 (Sollseite des Kontos)
> 148213099998     18430     311003        000135425 (Habenseite des Kontos)
>           1         2         3         4         5         6
>           7

Ich verstehe nicht ganz, was obiges genau darstellen soll, um ehrlich zu
sein.

> 12345678901234567890123456789012345678901234567890123456789012345678901234567890
> llmmmmmnnnnnooooopppppqqqqqrrrrrrssssssttuuuuuuuuuvvvvvvvvvvvvvvvvvvwwxxxxxyyyyy
> l = Satzart n
[...]
> y = Kostenträger

Das Ausschneiden erfolgt mit obiger Funktion.

> Die Eingabe-Datei für obige Daten heißt FB82130.DAV

[...]
>>>- erstellen einer "Saldenliste" Saldenliste ist eine Zeile je Konto
>>>  Anfangsbestand laut Eröffnungswert im Kontensatz
>>>  + und - der Bewegungszahlen (aus Buchungen)
>>>  errechnet: neuer Endwert
> Beispiel:
> Überschrift: Saldenliste Mandant 82130 vom 31.12.2003, Seite : 1

> Konto Bezeichnung Anfangssaldo Umsatz-Soll Umsatz-Haben Endsaldo
> ccccc ggg...ggggg hhhhhhhhh,hh uuuuuuu,uu   uuuuuuu,uu  zzzzzzzzz,zz

Als Dezimaltrenner scheint ein Komma verwendet zu werden.

> wobei h + uS - uH = z ist.

> wenn n = 99998, dann ist u = uH,
> wenn p = 99998, dann ist u = uS

Interessant sind hier also: Die jeweilige Kontonummer, die Bezeichnung,
und der Umsatz. Konto ist das, was du als Unterkonto bezeichnest? Also o
und q? Wie berechnest du das Anfangssaldo? Als Übertrag vom Endsaldo aus
der vorhergehenden Zeile? (und 0 zu Beginn?). 

Da mir dies noch nicht so klar ist, kann ich dir keine Beispiellösung
geben. Hier nur ein Ansatz:

import time

def substrings (s, *indice):
    return [s[beg-1:end] for (beg, end) in indice]

def proc_mand (mand, fun):
    inf = file('FB' + mand + '.DAV')
    fun(inf, mand)
    inf.close()

def write_sald (inf, mand):
    outf = file('SALD' + mand + '.TXT', 'w')
    outf.write('Saldenliste Mandant %s vom %s, Seite 1 :\n' %
               (mand, time.strftime('%d.%m.%Y')))
    outf.write('Konto Bezeichnung Anfangssaldo Umsatz-Soll Umsatz-Haben Endsaldo\n')
    for line in inf:
        soll, sk, haben, hk, bez, wert = substring(line, (8,12),(13,17),(18,22),
                                                   (23,26),(51,68),(42,50))
        .
        .
        .
    outf.close()

Die letzte Funktion (write_saldo) ist noch unvollständig (wegen der
Fragen). Aber das Prinzip sollte klar sein. Du hättest eine Funktion
proc_mand(), die als Argumente die Mandantennummer und eine Funktion,
die die eigentliche Arbeit erledigt bekommt (ob die Aufteilung so
günstig für dich ist, weiß ich nicht). Man könnte auch daran denken,
eine Klasse (Mandantendatei) zu schreiben, die die einzelnen
Auswertungsmöglichkeiten als Methoden enthält. Dies ist aber leicht
anzupassen, wenn das Grobgerüst steht.

HTH

   Karl
-- 
The PROPER way to handle HTML postings is to cancel the article,
then hire a hitman to kill the poster, his wife and kids, and fuck
his dog and smash his computer into little bits. Anything more is
just extremism.                                 -- Paul Tomblin, asr