::Tips & Tricks / Verschiedenes / Perl / 9. Beispielprojekt Seite drucken
  der verein   projekte   veranstaltungen   hilfestellung   tips & tricks   fun   
 
  
  grundsĂ€tzliches
  
  fenstermanager
  
  web, mail & news
  
  multimedia
  
  novell/suse
  
  gentoo
  
  VERSCHIEDENES
 externe usb-platten mounten
 datenrettung
 perl
  
  links


home
sitemap
suche
login
hilfeforum
impressum



Finde uns auf:
 

9. Ein grĂ¶ĂŸeres Beispiel

Das Beispielprogramm wertet einen Einzelverbindungsnachweis der KomTel aus und liefert als Ergebnis eine Datei mit abweichenden GesprÀchspreisen. Die Differenz in den GesprÀchspreisen beruht auf der Aufrundung jedes angefangenen Pfennigs auf den nÀchsten vollen Pfennig. Auf diese Art können erhebliche Differenzen entstehen.

 

Der EVN wird per EMail verschickt. EMail-Programme, z.B. Netscape, speichern die Mail komplett mit den Headern. Dieser muß von dem Programm ignoriert werden. Die einzelnen Zeilen haben das folgende Format:

<typocode>

Vorwahl;Durchwahl;Datum;Uhrzeit;Art.-Nr.;Zielvorwahl;Zieldurchwahl;Dauer (Min./Sek.);Brutto-Preis;Projektnr

 

04xxx;8xxx;01.12.99;19:47:58;KomTel Online;0045012;3461;00:07:43;0,78;

</typocode>

9.1 Programmstart und Module

Die in UNIX ĂŒbliche Startzeile sollte auch in Windows Perl-Programmen vorhanden sein - das schadet nicht und erleichtert die PortabilitĂ€t.

 

Der Programmzweck und evtl. nötige Startparameter sind an dieser Stelle gĂŒnstig als GedĂ€chtnisstĂŒtze untergebracht. Ein wenig Programmgeschichte ist gelegentlich auch ganz nett.

Das Module DateCalc verhindert die Neuerfindung des Rades. Das Modul ist auf CPAN - modules - moduules by name - Date zu finden.

 

Die in der lokalen Perlinstallation enthaltenen Module können mit perldoc perllocal abgefragt werden.

<typocode>

#!/usr/bin/perl

#

# ueberpruefung der komtel-internet-Rechnung

#

# CALL : chkabr datei

#

# PARAMETER: datei - Name der einzulesenden Datei

#

use Date::Calc qw(:all);

</typocode>

9.2 Nötige Definitionen

Die einzige Benutzeranpassung liegt in der Variablen $vorw. Dieser String wird benutzt um einzelne Rechnungszeilen sicher zu identifizieren. Anhand der Vorwahl und der Telefonnummer wird erst die Auswertung einer Zeile eingeleitet. Diese Daten sollten sonst nirgends in einem EVN auftauchen. NatĂŒrlich kann das auch ein beliebiger anderer String sein. Die Bedingung ist einfach: Der String darf außer in den Zeilen mit den GesprĂ€chen nirgends im EVN auftauchen, hier muß er jedoch stehen.

<typocode>

$vorw = "4xxx;8xxx";

 

#

# Zeiger fuer Tariftabelle aufsetzen

# weitere Tarife mit Namen und laufender Nummer anfuegen

#

%thistos = (

"KomTel Online", 0,

"Deutschland", 1,

"Nord-Ostsee", 2,

"Schleswig-Holstein", 3,

"Mobil", 4,

);

 

#

# Tabelle fuer die Tarife

# Preis in Pfennig/Min. fuer jedes Stunde des Tages

#

@value = (

6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 6, 6, 6,

10, 10, 10, 10, 10, 10, 10, 10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10,

10, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 10, 10, 10, 10,

6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 6, 6, 6,

70, 70, 70, 70, 70, 70, 70, 70, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 70, 70, 70, 70,

);

 

@wota = ("err", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So");

 

$i = 0;

</typocode>

9.3 A little magic

FĂŒr die korrekte Abrechnung ist nicht nur die Tageszeit wichtig sondern auch der Wochentag. Außerdem sind die Feiertage zu berĂŒcksichtigen. Bei dieser Aufgabe hilft das Module DateCalc. Die einzelnen Feiertage sind als Offset zum Ostersonntag definiert und können dadurch leicht mit Hilfe des Moduls ermittelt werden.

 

Die anderen Feiertage werden einfach als feste Daten in das Array aufgenommen.

 

ZunĂ€chst muß aber das Jahr des EVN vierstellig ermittelt werden. Dazu wird die EVN-Datei geöffnet und die erste GesprĂ€chszeile ausgewertet.

<typocode>

#

# erste Rechnungszeile suchen, Datum isolieren und Jahr feststellen

#

open (ABRECHNUNG, $ARGV[0]) or die "$ARGV[0] $!";

while (<ABRECHNUNG>)

{

if (index($_, "Vorwahl;Durch") < 0)

{

last;

}

} # while

 

while (<ABRECHNUNG>)

{

if (index($_, $vorw) < 0)

{

next;

}

 

($vw, $ddi, $datum, $t, $tos, $f, , $f, $dur, $dm, $f) = split(/;/);

last;

}

close ABRECHNUNG;

 

($dd, $mm, $year) = split(/\./, $datum); # Wochentag ermitteln

$thisyear = $year >= 100? $year : $year + ($year < 98? 2000 : 1900);

 

 

#

# Feiertage ermitteln: 1.1., 3.10., 25.12, 26.12, Oster- und Pfingstmontag

#

($fm[$i], $fd[$i++]) = (1, 1);

($f, $fm[$i], $fd[$i++]) = Add_Delta_Days(Easter_Sunday($thisyear), -2);

($f, $fm[$i], $fd[$i++]) = Add_Delta_Days(Easter_Sunday($thisyear), 1);

($f, $fm[$i], $fd[$i++]) = Add_Delta_Days(Easter_Sunday($thisyear), 39);

($f, $fm[$i], $fd[$i++]) = Add_Delta_Days(Easter_Sunday($thisyear), 50);

($fm[$i], $fd[$i++]) = (10, 3);

($fm[$i], $fd[$i++]) = (12, 25);

($fm[$i], $fd[$i++]) = (12, 26);

 

$i = 0;

$komsum = 0,0;

</typocode>

9.4 Ein- und Ausgabdateien

Zwei Dateien werden geöffnet: Die auf der Kommandozeile ĂŒbergebene und eine weitere mit einem angehĂ€ngten vgl.

<typocode>

#

# abrechnungs-email und ergebnis-datei oeffnen

#

open (ABRECHNUNG, $ARGV[0]) or die "$ARGV[0] $!";

open (ERGEBNIS, ">$ARGV[0].vgl") or die "$0: $ARGV[0].vgl - $!";

</typocode>

9.5 Nicht alles ist wichtig

Diese Zeilen dienen den evtl. gespeicherten EMail-Kopf zu ĂŒbergehen. Es wird die Kopfzeile fĂŒr die GesprĂ€che gesucht.

<typocode>

#

# den email-header uebergehen

#

while (<ABRECHNUNG>)

{

if (index($_, "Vorwahl;Durch") < 0)

{

last;

}

 

} # while

</typocode>

9.6 Die eigentliche Aufgabe

Hier wird jetzt Zeile fĂŒr Zeile bearbeitet. Das Datum wird genutzt um den Wochentag zu ermitteln. Der Startzeitpunkt und die GesprĂ€chszeit werden in Sekunden umgerechnet.

 

FĂŒr jede Stunde des Tages wird der Anteil des GesprĂ€chs in einer Zeile dargestellt. NatĂŒrlich nur falls das GesprĂ€ch nicht ĂŒber einen Stundenwechsel ging.

<typocode>

#

# Datei bis zum Ende verarbeiten

#

while (<ABRECHNUNG>)

{

if (index($_, $vorw) < 0)

{

next;

}

 

($vw, $ddi, $datum, $t, $tos, $f, , $f, $dur, $dm, $f) = split(/;/);

 

$dm =~ s/,/./; # komma durch punkt ersetzen - sonst keine nachkst.

 

$line = "";

$komsum += $dm; # summe der KomTel berechnen

 

($dd, $mm, $year) = split(/\./, $datum); # Wochentag ermitteln

$year = $year >= 100? $year : $year + ($year < 98? 2000 : 1900);

$wt = Day_of_Week($year, $mm, $dd);

 

($hour, $min, $sec) = split(/:/, $dur);

$totsec = $hour * 3600 + $min * 60 + $sec;

 

($hour, $min, $sec) = split(/:/, $t);

$startsec = $hour * 3600 + $min * 60 + $sec; # Startsekunde am Tag ermitteln

 

$h1 = int($startsec / 3600); # stunde in der der call begann

$hr = 3600 - ($startsec - 3600 * $h1); # restsekunden in dieser stunde

$line .= sprintf ("%s %s %s %s %6d %.2f\n", $wota[$wt], $datum, $t, $dur, $totsec, $dm);

 

&chk_day;

 

$mydm = 0;

if ($hr > $totsec) # nicht bis zum ende der stunde

{

$mydm += $totsec * $v;

$line .= sprintf(" %2d %4d %6.4f %.3f\n", $h1, $totsec, $v, $v * $totsec);

$totsec = 0;

}

else

{

$mydm += $hr * $v;

$totsec -= $hr;

$line .= sprintf(" %2d %4d %.6f %.3f\n", $h1, $hr, $v, $v * $hr);

}

 

while ($totsec > 0)

{

$h1++;

 

if ($h1 > 23) # datumswechsel

{

$h1 = 0;

($year, $mm, $dd) = Add_Delta_Days($year, $mm, $dd, 1);

$wt = Day_of_Week($year, $mm, $dd);

}

 

&chk_day;

 

if ($totsec > 3600)

{

$mydm += 3600 * $v;

$line .= sprintf(" %2d %4d %.6f %.3f\n", $h1, 3600, $v, $v * 3600);

}

else

{

$mydm += $totsec * $v;

$line .= sprintf(" %2d %4d %.6f %.3f\n", $h1, $totsec, $v, $v * $totsec);

}

 

$totsec -= 3600;

 

} # while

 

# if (abs($dm - $mydm) > .01)

# {

print ERGEBNIS $line;

print ERGEBNIS " ";

printf ERGEBNIS ("%5.3f\n\n", $mydm);

# }

$sum += $mydm;

$i++;

 

} # while

 

printf ERGEBNIS ("%d %6.2f %6.2f\n", $i, $sum, $komsum);

 

close ABRECHNUNG;

close ERGEBNIS;

 

exit;

</typocode>

9.7 Wochentage sind wichtig

Der Wert der GesprÀchssekunden pro Stunde wird in AbhÀnngigkeit des Wochentags ermittelt. Falls Das GesprÀch an einem Feiertag stattgefunden hat, wird der Preis der Stunde 0 des Tages angesetzt.

<typocode>

#

# ueberpruefe den wochentag

# samstag und sonntag sind pauschal 6 pf/min

# ueberpruefe gewisse feiertage

#

sub chk_day

{

if (($wt == 6) || ($wt == 7)) # Samstag, Sonntag: Preis Stunde 0

{

$v = $value[$thistos{$tos} * 24] / 100 / 60;

return;

}

else

{

$v = $value[$thistos{$tos} * 24 + $h1] / 100 / 60;

}

 

#

# Feiertage: Array durchsuchen

# Preis wie an Sonntagen -> Stunde 0

#

for ($n = 0; $n < $#fd; $n++)

{

if ($dd == $fd[$n] && $mm == $fm[$n])

{

$v = $value[$thistos{$tos} * 24] / 100 / 60;

return;

}

}

} # chk_day

 

# eof

</typocode>

9.8 Die Ausgabe

Eine Zeile aus einem EVN

<typocode>

04xxx;8xxx;27.12.99;20:10:53;KomTel Online;0045012;3461;00:59:14;3,55;

</typocode>

wird vom Programm mit den wichtigsten Daten erneut ausgegeben: Wochentag, Datum, Startzeitpunkt, Dauer in hh:mm:ss und Sekunden sowie den Brutto-Preis lt. EVN.

 

Anschließend folgen fĂŒr jede Stunde der Verbindung wird die Stunde, die Sekunden in dieser Stunde, der Preis pro Sekunde sowie der Preis fĂŒr diese Stunde ausgegeben.

 

Als letzte Zeile wird der Gesamtpreis der Verbindung ausgegeben.

<typocode>

Mo 27.12.99 20:10:53 00:59:14 3554 3.55

20 2947 0.001000 2.947

21 607 0.001000 0.607

3.554

</typocode>

Am Ende der Datei steht eine Zeile mit der Anzahl der GesprÀche, der Summe und der Summe der EinzelbetrÀge laut EVN.

9.9 Known bugs

Die Daten eines EVN dĂŒrfen nicht ĂŒber einen Jahreswechsel gehen. Da die Jahreszahl fĂŒr die Feiertage anhand der ersten GesprĂ€chszeile ermittelt wird, sind die Feiertage (Ostern, Pfingsten) eines evtl folgenden Jahres nicht in der Feiertagsliste enthalten.

 

Der 1.1. ist noch in Ordnung.

 

Abhilfe schafft ein aufspalten des EVN in mehrere Dateien.