1package Parse::PhoneNumber;
2use strict;
3use warnings;
4
5use Carp;
6
7use vars qw[$VERSION $EXT $MINLEN $MIN_US_LENGTH @CCODES];
8
9$VERSION = qw(1.9);
10$EXT     = qr/\s*(?:(?:ext|ex|xt|x)[\s.:]*(\d+))/i;
11
12$MINLEN        = 7;
13$MIN_US_LENGTH = 10;
14
15@CCODES  = qw[
16	1	7	20	27	30	31	32	33	34
17	36	39	40	41	43	44	45	46	47
18	48	49	51	52	53	54	55	56	57
19	58	60	61	62	63	64	65	66	81
20	82	84	86	90	91	92	93	94	95
21	98	212	213	216	218	220	221	222	223
22	224	225	226	227	228	229	230	231	232
23	233	234	235	236	237	238	239	240	241
24	242	243	244	245	246	247	248	249	250
25	251	252	253	254	255	256	257	258	260
26	261	262	263	264	265	266	267	268	269
27	290	291	297	298	299	350	351	352	353
28	354	355	356	357	358	359	370	371	372
29	373	374	375	376	377	378	380	381	385
30	386	387	388	389	420	421	423	500	501
31	502	503	504	505	506	507	508	509	590
32	591	592	593	594	595	596	597	598	599
33	670	672	673	674	675	676	677	678	679
34	680	681	682	683	684	685	686	687	688
35	689	690	691	692	800	808	850	852	853
36	655	856	870	871	872	873	874	878	880
37	881	882	886	960	961	962	963	964	965
38	966	967	968	970	971	972	973	974	975
39	976	977	979	991	992	993	994	995	996
40	998
41];
42
43=head1 NAME
44
45Parse::PhoneNumber - Parse Phone Numbers
46
47=head1 SYNOPSIS
48
49 use Parse::PhoneNumber;
50 my $number = Parse::PhoneNumber->parse( number => $phone );
51
52 print $number->human;
53
54=head1 ABSTRACT
55
56Parse phone numbers.  Phone number have a defined syntax (to a point),
57so they can be parsed (to a point).
58
59=head1 DESCRIPTION
60
61=head2 Methods
62
63=head3 new
64
65Create a new Parse::PhoneNumber object.  Useful if a lot of numbers
66have to be parsed.
67
68=cut
69
70sub new {
71	return bless {}, shift;
72}
73
74=head3 parse
75
76Accepts a list of arguments.  C<number> is the phone number.  This method
77will return C<undef> and set C<errstr> on failure.  On success, a
78C<Parse::PhoneNumber::Number> object is returned. C<assume_us> will have
79the country code default to C<1> if none is given.  This is due to the fact
80that most people in the US are clueless about such things.
81
82=cut
83
84sub parse {
85	my ($class, %data) = @_;
86	croak "No phone number" unless $data{number};
87
88	local $_  = $data{number};
89	s/^\s+//;s/\s+$//;
90
91	my %number = (
92		orig    => $data{number},
93		cc      => undef,
94		num     => undef,
95		ext     => undef,
96		opensrs => undef,
97		human   => undef,
98	);
99
100
101
102	if ( m/$EXT$/ ) {
103		if ( length $1 > 4 ) {
104			$class->errstr( "Extension '$1' longer than four digits" );
105			return undef;
106		} else {
107			$number{ext} = $1;
108			s/$EXT$//;
109		}
110	}
111
112	s/\D//g;
113	s/^0+//;
114
115	if ($data{'assume_us'}) {
116		if (length $_ < $MIN_US_LENGTH) {
117			$class->errstr("Invalid US number: $data{number}" );
118			return;
119		} else {
120			$number{'cc'}  = 1;
121			s/^1//;
122			$number{'num'} = $_;
123		}
124	} else {
125
126		foreach my $len ( 1 .. 3 ) {
127			last if $number{cc};
128
129			my $cc = substr $_, 0, $len;
130
131			if ( grep { $_ eq $cc } @CCODES ) {
132				$number{cc} = $cc;
133				s/^$cc//;
134			}
135		}
136
137		if ( $number{cc} && length "$number{cc}$_" >= $MINLEN ) {
138			$number{num}  = "$_";
139		} else {
140			$class->errstr("Invalid international number: $data{number}" );
141			return undef;
142		}
143	}
144
145	$number{opensrs}  = sprintf "+%d.%s", @number{qw[cc num]};
146	$number{opensrs} .= sprintf "x%d", $number{ext} if $number{ext};
147
148	$number{human}  = sprintf "+%d %s", @number{qw[cc num]};
149	$number{human} .= sprintf " x%d", $number{ext} if $number{ext};
150
151	return Parse::PhoneNumber::Number->new( %number );
152}
153
154=head3 errstr
155
156Returns the last error reported, or undef if no errors have occured yet.
157
158=cut
159
160{
161	my $errstr = undef;
162	sub errstr { $errstr = $_[1] if $_[1]; $errstr }
163	sub clear_errstr { $errstr = undef; }
164}
165
166package Parse::PhoneNumber::Number;
167use strict;
168use warnings;
169
170=head2 Parse::PhoneNumber::Number Objects
171
172The objects returned on a successful parse.
173
174=cut
175
176sub new {
177	my ($class, %data) = @_;
178	return bless \%data, $class;
179}
180
181=head3 orig
182
183The original string passed to C<parse>.
184
185=head3 cc
186
187The Country Code
188
189=head3 num
190
191The phone number, including the trunk pointer, area code, and
192subscriber number.
193
194=head3 ext
195
196An extension, if one is present.
197
198=head3 opensrs
199
200The format an OpenSRS Registrar must make a phone number for some
201TLDs.
202
203=head3 human
204
205Human readable format.
206
207=cut
208
209sub orig    { $_[0]->{orig}    }
210sub cc      { $_[0]->{cc}      }
211sub num     { $_[0]->{num}     }
212sub ext     { $_[0]->{ext}     }
213sub opensrs { $_[0]->{opensrs} }
214sub human   { $_[0]->{human}   }
215
2161;
217
218__END__
219
220=head1 BUGS
221
222Currently only accept phone numbers in International format.  If a
223number isn't given in international format, a false positive could
224occur.
225
226Please report bugs to the CPAN RT instance at
227L<https://rt.cpan.org/Dist/Display.html?Queue=Parse-PhoneNumber>
228
229=head1 SEE ALSO
230
231L<Number::Phone>
232
233=head1 AUTHOR
234
235Casey West <F<casey@geeknest.com>>
236
237Maintained by Tim Wilde <F<cpan@krellis.org>>
238
239=head1 COPYRIGHT
240
241Copyright (c) 2003 Casey West <casey@geeknest.com>.
242
243Portions Copyright (c) 2005 Dynamic Network Services, Inc.
244
245Portions Copyright (c) 2011 Tim Wilde
246
247Portions Copyright (c) 2012 Google, Inc.
248
249All rights reserved.
250
251This program is free software; you can redistribute it
252and/or modify it under the same terms as Perl itself.
253