Description: |
Parse the phone bill given by Orange cellphone company (www.orange.net)
It shows the information per phone number (number of calls and text messages, and the cost/minute). I use it to check which of my friends costs me the most :)
I'm now in the UK and this is the bill they give here, but this might work in other countries. In case there's a problem with other countries, let me know.
|
#!/usr/bin/perl -w
#
# Summarize Orange's phone bill.
#
use strict;
# This optional file holds known phone numbers. Each line contains a
# "name: phone" pair (i.e. separated by a colon)
my $phonefile = "../phones";
# The international phone country prefix:
my $country_prefix = "44";
my %numbers;
if (-f $phonefile) {
print "Reading the phone list from $phonefile\n";
open(F, "<$phonefile") or die "Can't read phone file";
while(<F>) {
next if /^$/;
my ($name, $number) = split(/:/); #m/([^:]+):(.+)/;
die ("Parse error in $phonefile line $.") unless defined($name) an
+d defined($number);
next unless defined($name);
$number =~ s/\s//g;
$numbers{$number} = $name;
}
}
$numbers{''} = "Unknown";
# Add variations on the numbers:
foreach (sort keys %numbers) {
my ($k)=$_;
s/ //g;
$numbers{$_} = $numbers{$k};
s/^0(?=[1-9])/$country_prefix/;
$numbers{$_} = $numbers{$k};
}
my %costs;
my %calls;
my %texts;
my %totals;
my %durations;
my $count =0;
my $tot=0;
my $thedate;
# File format:
# Date Day Time Number Place called Call Service plan Duration Cost
# 19/01/02 Sat 00:07 07957543534 Other Mobile Network talk 0:00:06 0.0
+10
# 08:02 02076345454 Inner London talk talk 0:13:28 0.000
while (<>) {
next unless /^Date\s* Day\s* Time\s* Number/ .. eof(); # Skip the
+header
my ($date,$day,$time,$number,$place,$class,$service,$duration,$cos
+t) =
m<((?:\d\d\/\d\d\/\d\d)*) # Possible date
\s*(\w*) # Possible day of week
\s*(\d\d:\d\d) # Time of call
\s*([\d+]*) # Number
#\s*((?:(?:\w+\s)+|\(\w+\))+) # Place called
\s*(.*(?=talk|text|data)) # Place called
\s*(talk|text|data) # Call class
\s*(\w*) # Possible Service Plan
\s*(\d+:\d\d:\d\d) # Duration
\s*([\d.]+) # Cost
>x;
if (defined($cost)) {
#print "$count : $time $number $place\n";
$count++;
$tot += $cost;
if (defined($numbers{$number})) { $number = $numbers{$number} };
$costs{$number}+= $cost;
if($class eq 'talk') {
$calls{$number}++;
} elsif ($class eq 'text' || $class eq 'data') {
$texts{$number}++;
} else {
print "Unknown class '$class' for number '$number'\n";
}
my ($h,$m,$s) = $duration=~m/(\d+):(\d+):(\d+)/;
$durations{$number} += $s + 60*($m + 60*$h);
}
if(/^\s*(Sub total|Total)\s+£(.*)/ ) { # (correctness check)
if (abs($2 - $tot)>0.01 and $#ARGV==1) {
print "$#ARGV\n";
print join "\n", @ARGV;
printf("\nERROR: Line $., %5.2f != %5.2f by %f\n",
$2, $tot, abs($2-$tot));
exit;
}
}
}
my $bill = 0;
my $airtime = 0;
for (sort keys %costs) {
$calls{$_}=0 unless defined($calls{$_});
$texts{$_}=0 unless defined($texts{$_});
my $per = $durations{$_}>0 ? 100*$costs{$_}/$durations{$_} : 0;
printf("%-20s : %10s %3dt %3dc £%5.2f %5.2f ¢/s\n", $_,
&timeprint($durations{$_}), $texts{$_}, $calls{$_}, $costs{$_},
$per);
$bill += $costs{$_};
$airtime += $durations{$_};
}
printf("Total $count calls (%s), %d numbers, $bill pounds\n", timepri
+nt($airtime), scalar keys(%costs));
sub timeprint {
my $t = shift;
my $o;
if ($t < 60) {
$o = "$t"."s";
} elsif ($t<60*60) {
$o = sprintf "%2dm%2ds", int($t/60), $t%60;
} else {
my $r = $t%3600;
$o = sprintf "%2dh%2dm%2ds", ($t-$r)/3600, int($r/60), $r%60;
}
$o
}
|