::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:


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;

 


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.


#!/usr/bin/perl

#

# ueberpruefung der komtel-internet-Rechnung

#

# CALL : chkabr datei

#

# PARAMETER: datei - Name der einzulesenden Datei

#

use Date::Calc qw(:all);

 


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.


$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;

 


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.


#

# 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;

 


9.4 Ein- und Ausgabdateien

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


#

# 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 - $!";

 


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.


#

# den email-header uebergehen

#

while (<ABRECHNUNG>)

{

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

{

last;

}


} # while

 


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.


#

# 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;

 


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.


#

# 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

 


9.8 Die Ausgabe

Eine Zeile aus einem EVN


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

 

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.


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

 

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.