Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Summarize Orange phone bill

by fundflow (Chaplain)
on Apr 03, 2002 at 09:21 UTC ( #156270=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info /msg fundflow
Description: Parse the phone bill given by Orange cellphone company (

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

    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

    if (defined($cost)) {
    #print "$count : $time $number $place\n";
    $tot += $cost;

    if (defined($numbers{$number})) { $number = $numbers{$number} };
    $costs{$number}+= $cost;
    if($class eq 'talk') {
    } elsif ($class eq 'text' || $class eq 'data') {
    } 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));

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{$_},
    $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;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://156270]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (1)
As of 2018-01-22 06:27 GMT
Find Nodes?
    Voting Booth?
    How did you see in the new year?

    Results (232 votes). Check out past polls.