File Coverage

blib/lib/Locale/SubCountry.pm
Criterion Covered Total %
statement 107 130 82.3
branch 22 36 61.1
condition n/a
subroutine 22 25 88.0
pod 11 13 84.6
total 162 204 79.4


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Locale::SubCountry - Convert state, province, county etc. names to/from ISO 3166-2 codes, get all states in a country
4              
5             =head1 SYNOPSIS
6              
7             use Locale::SubCountry;
8            
9             my $fr = Locale::SubCountry->new('France');
10             if ( not $fr )
11             {
12             die "Invalid country or code: France\n";
13             }
14             else
15             {
16             print($fr->country,"\n"); # France
17             print($fr->country_code,"\n"); # FR
18             print($fr->country_number,"\n"); # 250
19              
20             if ( $fr->has_sub_countries )
21             {
22             print($fr->code('Hautes-Alpes '),"\n"); # 05
23             print($fr->full_name('03'),"\n"); # Allier
24             my $upper_case = 1;
25             print($fr->full_name('02',$upper_case),"\n"); # AINSE
26             print($fr->level('02'),"\n"); # Metropolitan department
27             print($fr->level('A'),"\n"); # Metropolitan region
28             print($fr->level('BL'),"\n"); # Overseas territorial collectivity
29             print($fr->levels,"\n"); # Metropolitan region => 22, Metropolitan department => 96 ...
30            
31             my @fr_names = $fr->all_full_names; # Ain, Ainse, Allier...
32             my @fr_codes = $fr->all_codes; # 01, 02, 03 ...
33             my %fr_names_keyed_by_code = $fr->code_full_name_hash; # 01 => Ain...
34             my %fr_codes_keyed_by_name = $fr->full_name_code_hash; # Ain => 01 ...
35              
36             foreach my $code ( sort keys %fr_names_keyed_by_code )
37             {
38             printf("%-3s : %s\n",$code,$fr_names_keyed_by_code{$code});
39             }
40             }
41             }
42              
43             # Methods for fetching all country codes and names in the world
44              
45             my $world = Locale::SubCountry::World->new();
46             my @all_countries = $world->all_full_names;
47             my @all_country_codes = $world->all_codes;
48              
49             my %all_countries_keyed_by_name = $world->full_name_code_hash;
50             my %all_country_keyed_by_code = $world->code_full_name_hash;
51              
52              
53             =head1 DESCRIPTION
54              
55             This module allows you to convert the full name for a country's administrative
56             region to the code commonly used for postal addressing. The reverse look up
57             can also be done.
58              
59             Lists of sub country codes are useful for web applications that require a valid
60             state, county etc to be entered as part of a users location.
61              
62             Sub countries are termed as states in the US and Australia, provinces
63             in Canada and counties in the UK and Ireland. Other terms include region,
64             department, city and territory. Countries such as France have several
65             levels of sub countries, such as Metropolitan department, Metropolitan region etc.
66              
67             Names and ISO 3166-2 codes for all sub countries in a country can be
68             returned as either a hash or an array.
69              
70             Names and ISO 3166-1 codes for all countries in the world can be
71             returned as either a hash or an array. This in turn can be used to
72             fetch every sub country from every country (see examples/demo.pl).
73              
74             Sub country codes are defined in "ISO 3166-2,
75             Codes for the representation of names of countries and their subdivisions".
76              
77              
78             =head1 METHODS
79              
80             Note that the following methods duplicate some of the functionality of the
81             Locale::Country module (part of the Locale::Codes bundle). They are provided
82             here because you may need to first access the list of countries and
83             ISO 3166-1 codes, before fetching their sub country data. If you only need
84             access to country data, then Locale::Country should be used.
85              
86             Note also the following method names are also used for sub country objects.
87             (interface polymorphism for the technically minded). To avoid confusion, make
88             sure that your chosen method is acting on the correct type of object.
89              
90             all_codes
91             all_full_names
92             code_full_name_hash
93             full_name_code_hash
94              
95              
96             =head2 Locale::SubCountry::World->new()
97              
98             The C method creates an instance of a world country object. This must be
99             called before any of the following methods are invoked. The method takes no
100             arguments.
101              
102              
103             =head2 full_name_code_hash (for world objects)
104              
105             Given a world object, returns a hash of full name/code pairs for every country,
106             keyed by country name.
107              
108             =head2 code_full_name_hash for world objects)
109              
110             Given a world object, returns a hash of full name/code pairs for every country,
111             keyed by country code.
112              
113              
114             =head2 all_full_names (for world objects)
115              
116             Given a world object, returns an array of all country full names,
117             sorted alphabetically.
118              
119             =head2 all_codes (for world objects)
120              
121             Given a world object, returns an array of all country ISO 3166-1 codes,
122             sorted alphabetically.
123              
124              
125             =head2 Locale::SubCountry->new()
126              
127             The C method creates an instance of a sub country object. This must be
128             called before any of the following methods are invoked. The method takes a
129             single argument, the name of the country that contains the sub country
130             that you want to work with. It may be specified either by the ISO 3166-1
131             alpha-2 code or the full name. For example:
132              
133             AF - Afghanistan
134             AL - Albania
135             DZ - Algeria
136             AO - Angola
137             AR - Argentina
138             AM - Armenia
139             AU - Australia
140             AT - Austria
141              
142              
143             If the code is specified, such as 'AU' the format may be in capitals or lower case
144             If the full name is specified, such as 'Australia', the format must be in title case
145             If a country name or code is specified that the module doesn't recognised, it will issue a warning.
146              
147             =head2 country
148              
149             Returns the current country name of a sub country object. The format is in title case,
150             such as 'United Kingdom'
151              
152             =head2 country_code
153              
154             Given a sub country object, returns the alpha-2 ISO 3166-1 code of the country,
155             such as 'GB'
156              
157              
158             =head2 code
159              
160             Given a sub country object, the C method takes the full name of a sub
161             country and returns the sub country's alpha-2 ISO 3166-2 code. The full name can appear
162             in mixed case. All white space and non alphabetic characters are ignored, except
163             the single space used to separate sub country names such as "New South Wales".
164             The code is returned as a capitalised string, or "unknown" if no match is found.
165              
166             =head2 full_name
167              
168             Given a sub country object, the C method takes the alpha-2 ISO 3166-2 code
169             of a sub country and returns the sub country's full name. The code can appear
170             in mixed case. All white space and non alphabetic characters are ignored. The
171             full name is returned as a title cased string, such as "South Australia".
172              
173             If an optional argument is supplied and set to a true value, the full name is
174             returned as an upper cased string.
175              
176             =head2 level
177              
178             Given a sub country object, the C method takes the alpha-2 ISO 3166-2 code
179             of a sub country and returns the sub country's level . Examples are city,
180             province,state and district, and usually relates to the a regions size.
181             The level is returned as a string, or "unknown" if no match is found.
182              
183              
184             =head2 has_sub_countries
185              
186             Given a sub country object, the C method returns 1 if the
187             current country has sub countries, or 0 if it does not. Some small countries
188             such as New Caledonia" do not have sub countries.
189              
190              
191             =head2 full_name_code_hash (for sub country objects)
192              
193             Given a sub country object, returns a hash of all full name/code pairs,
194             keyed by sub country name. If the country has no sub countries, returns undef.
195              
196             =head2 code_full_name_hash (for sub country objects)
197              
198             Given a sub country object, returns a hash of all code/full name pairs,
199             keyed by sub country code. If the country has no sub countries, returns undef.
200              
201              
202             =head2 all_full_names (for sub country objects)
203              
204             Given a sub country object, returns an array of all sub country full names,
205             sorted alphabetically. If the country has no sub countries, returns undef.
206              
207             =head2 all_codes (for sub country objects)
208              
209             Given a sub country object, returns an array of all sub country alpha-2 ISO 3166-2 codes.
210             If the country has no sub countries, returns undef.
211              
212              
213             =head1 SEE ALSO
214              
215             All codes have been downloaded from the latest version of the Debian Salsa project
216             L
217              
218              
219              
220             L,L,
221             L,L,L
222             L for obtaining ISO 3166-2 data
223              
224             ISO 3166-1 Codes for the representation of names of countries and their
225             subdivisions - Part 1: Country codes
226              
227             ISO 3166-2 Codes for the representation of names of countries and their
228             subdivisions - Part 2: Country subdivision code
229              
230              
231             L is a good source for sub country codes plus
232             other statistical data.
233              
234              
235             =head1 LIMITATIONS
236              
237             The ISO 3166-2 standard romanizes the names of provinces and regions in non-latin
238             script areas, such as Russia and South Korea. One Romanisation is given for each
239             province name. For Russia, the BGN (1947) Romanization is used.
240              
241             Several sub country names have more than one code, and may not return
242             the correct code for that sub country. These entries are usually duplicated
243             because the name represents two different types of sub country, such as a
244             province and a geographical unit. Examples are:
245              
246             AZERBAIJAN : Lankaran; LA (the Municipality), LAN (the Rayon) [see note]
247             AZERBAIJAN : Saki; SA,SAK [see note]
248             AZERBAIJAN : Susa; SS,SUS
249             AZERBAIJAN : Yevlax; YE,YEV
250             LAOS : Vientiane VI the Vientiane, VT the Prefecture
251             MOZAMBIQUE : Maputo; MPM (City),L (Province)
252              
253             Note: these names are spelt with diacrtic characters (such as two dots above
254             some of the 'a' characters). This causes utf8 errors on some versions
255             of Perl, so they are omitted here. See the Locale::SubCountry::Codes module
256             for correct spelling
257              
258              
259             =head1 AUTHOR
260              
261             Locale::SubCountry was written by Kim Ryan .
262              
263             =head1 COPYRIGHT AND LICENCE
264              
265             This software is Copyright (c) 2018 by Kim Ryan.
266              
267             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
268              
269              
270             =head1 CREDITS
271              
272             Ron Savage for many corrections to the data
273              
274              
275             Terrence Brannon produced Locale::US, which was the starting point for
276             this module.
277              
278              
279             =head1 COPYRIGHT AND LICENSE
280              
281             Copyright (c) 2019 Kim Ryan. All rights reserved.
282              
283             This library is free software; you can redistribute it and/or modify
284             it under the same terms as Perl itself.
285              
286             =cut
287              
288             #-------------------------------------------------------------------------------
289              
290             package Locale::SubCountry::World;
291 1     1   68380 use strict;
  1         3  
  1         31  
292 1     1   5 use warnings;
  1         2  
  1         31  
293 1     1   529 use locale;
  1         586  
  1         5  
294 1     1   39 use Exporter;
  1         2  
  1         38  
295 1     1   679 use JSON;
  1         12243  
  1         6  
296 1     1   2277 use Locale::SubCountry::Codes;
  1         4  
  1         1483  
297              
298             #-------------------------------------------------------------------------------
299              
300              
301             our $VERSION = '2.05';
302              
303             # Define all the methods for the 'world' class here. Note that because the
304             # name space inherits from the Locale::SubCountry name space, the
305             # package wide variables $SubCountry::country and $Locale::SubCountry::subcountry are
306             # accessible.
307              
308              
309             #-------------------------------------------------------------------------------
310             # Create new instance of a SubCountry::World object
311              
312             sub new
313             {
314 1     1   3 my $class = shift;
315              
316 1         3 my $world = {};
317 1         2 bless($world,$class);
318 1         3 return($world);
319             }
320              
321             #-------------------------------------------------------------------------------
322             # Returns a hash of code/name pairs for all countries, keyed by country code.
323              
324             sub code_full_name_hash
325             {
326 1     1   302 my $world = shift;
327 1         3 return( %{ $Locale::SubCountry::country{_code_keyed} } );
  1         214  
328             }
329             #-------------------------------------------------------------------------------
330             # Returns a hash of name/code pairs for all countries, keyed by country name.
331              
332             sub full_name_code_hash
333             {
334 1     1   5 my $world = shift;
335 1         3 return( %{ $Locale::SubCountry::country{_full_name_keyed} } );
  1         315  
336             }
337             #-------------------------------------------------------------------------------
338             # Returns sorted array of all country full names
339              
340             sub all_full_names
341             {
342 1     1   299 my $world = shift;
343 1         2 return ( sort keys %{ $Locale::SubCountry::country{_full_name_keyed} });
  1         145  
344             }
345             #-------------------------------------------------------------------------------
346             # Returns sorted array of all two letter country codes
347              
348             sub all_codes
349             {
350 1     1   301 my $world = shift;
351 1         3 return ( sort keys %{ $Locale::SubCountry::country{_code_keyed} });
  1         126  
352             }
353              
354             #-------------------------------------------------------------------------------
355              
356             package Locale::SubCountry;
357             our $VERSION = '2.05';
358              
359             #-------------------------------------------------------------------------------
360             # Initialization code which will be run first to create global data structure.
361             # Read in the list of abbreviations and full names defined in the
362             # Locale::SubCountry::Codes package
363              
364             {
365              
366             unless ( $Locale::SubCountry::Codes::JSON )
367             {
368             die "Could not locate Locale::SubCountry::Codes::JSON variable";
369             }
370              
371             # Get all the data from the Locale::SubCountry::Codes package and place into a structure
372              
373             # Note: will fail on badly formed JSON data
374             my $json_text = $Locale::SubCountry::Codes::JSON;
375             my $json = JSON->new->allow_nonref;
376            
377             my $all_codes_ref = $json->decode($json_text);
378            
379            
380             foreach my $country_ref ( @{ $all_codes_ref->{'3166-1'} })
381             {
382             # Create doubly indexed hash, keyed by country code and full name.
383             # The user can supply either form to create a new sub_country
384             # object, and the objects properties will hold both the countries
385             # name and it's code.
386              
387             $Locale::SubCountry::country{_code_keyed}{$country_ref->{alpha_2}} = $country_ref->{name};
388             $Locale::SubCountry::country{_full_name_keyed}{$country_ref->{name}} = $country_ref->{alpha_2};
389            
390             # Get numeric code for country, such as Australia = '036'
391             $Locale::SubCountry::country{$country_ref->{name}}{_numeric }= $country_ref->{numeric};
392             }
393              
394            
395             foreach my $sub_country_ref ( @{ $all_codes_ref->{'3166-2'} })
396             {
397             my ($country_code,$sub_country_code) = split(/\-/,$sub_country_ref->{code});
398             my $sub_country_name = $sub_country_ref->{name};
399            
400             $Locale::SubCountry::subcountry{$country_code}{_code_keyed}{$sub_country_code} = $sub_country_name;
401             $Locale::SubCountry::subcountry{$country_code}{_full_name_keyed}{$sub_country_name} = $sub_country_code;
402             $Locale::SubCountry::subcountry{$country_code}{$sub_country_code}{_level} = $sub_country_ref->{type};
403            
404             # Record level occurence in a country
405             $Locale::SubCountry::subcountry{$country_code}{_levels}{$sub_country_ref->{type}}++;
406            
407             }
408             }
409              
410             #-------------------------------------------------------------------------------
411             # Create new instance of a sub country object
412              
413             sub new
414             {
415 1     1 1 98 my $class = shift;
416 1         4 my ($country_or_code) = @_;
417              
418 1         3 my ($country,$country_code);
419              
420             # Country may be supplied either as a two letter code, or the full name
421 1 50       5 if ( length($country_or_code) == 2 )
422             {
423 0         0 $country_or_code = uc($country_or_code); # lower case codes may be used, so fold to upper case
424 0 0       0 if ( $Locale::SubCountry::country{_code_keyed}{$country_or_code} )
425             {
426 0         0 $country_code = $country_or_code;
427             # set country to it's full name
428 0         0 $country = $Locale::SubCountry::country{_code_keyed}{$country_code};
429             }
430             else
431             {
432 0         0 warn "Invalid country code: $country_or_code chosen";
433 0         0 return(undef);
434             }
435             }
436             else
437             {
438 1 50       7 if ( $Locale::SubCountry::country{_full_name_keyed}{$country_or_code} )
439             {
440 1         2 $country = $country_or_code;
441 1         4 $country_code = $Locale::SubCountry::country{_full_name_keyed}{$country};
442             }
443             else
444             {
445 0         0 warn "Invalid country name: $country_or_code chosen, names must be in title case";
446 0         0 return(undef);
447              
448             }
449             }
450              
451 1         2 my $sub_country = {};
452 1         3 bless($sub_country,$class);
453 1         7 $sub_country->{_country} = $country;
454 1         3 $sub_country->{_country_code} = $country_code;
455 1         4 $sub_country->{_numeric} = $Locale::SubCountry::country{$country}{_numeric};
456              
457              
458 1         3 return($sub_country);
459             }
460              
461             #-------------------------------------------------------------------------------
462             # Returns the current country's name of the sub country object
463              
464             sub country
465             {
466 0     0 1 0 my $sub_country = shift;
467 0         0 return( $sub_country->{_country} );
468             }
469             #-------------------------------------------------------------------------------
470             # Returns the current country's alpha2 code of the sub country object
471              
472             sub country_code
473             {
474 1     1 1 3 my $sub_country = shift;
475 1         6 return( $sub_country->{_country_code} );
476             }
477              
478             #-------------------------------------------------------------------------------
479             # Returns the current country's numeric code of the sub country object
480              
481             sub country_number
482             {
483 0     0 0 0 my $sub_country = shift;
484 0         0 return( $sub_country->{_numeric} );
485             }
486              
487             #-------------------------------------------------------------------------------
488             # Given the full name for a sub country, return the ISO 3166-2 code
489              
490             sub code
491             {
492 2     2 1 322 my $sub_country = shift;
493 2         5 my ($full_name) = @_;
494              
495 2 50       6 unless ( $sub_country->has_sub_countries )
496             {
497             # this country has no sub countries
498 0         0 return;
499             }
500              
501 2         4 my $orig = $full_name;
502              
503 2         7 $full_name = _clean($full_name);
504              
505 2         8 my $code = $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_full_name_keyed}{$full_name};
506              
507             # If a code wasn't found, it could be because the user's capitalization
508             # does not match the one in the look up data of this module. For example,
509             # the user may have supplied the sub country "Ag R" (in Turkey) but the
510             # ISO standard defines the spelling as "Ag r".
511              
512 2 100       7 unless ( defined $code )
513             {
514             # For every sub country, compare upper cased full name supplied by user
515             # to upper cased full name from lookup hash. If they match, return the
516             # correctly cased full name from the lookup hash.
517              
518 1         5 my @all_names = $sub_country->all_full_names;
519 1         3 my $current_name;
520 1         3 foreach $current_name ( @all_names )
521             {
522 8 50       21 if ( uc($full_name) eq uc($current_name) )
523             {
524 0         0 $code = $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_full_name_keyed}{$current_name};
525             }
526             }
527             }
528              
529 2 100       6 if ( defined $code )
530             {
531 1         8 return($code);
532             }
533             else
534             {
535 1         6 return('unknown');
536             }
537             }
538              
539             #-------------------------------------------------------------------------------
540             # Given the alpha-2 ISO 3166-2 code for a sub country, return the full name.
541             # Parameters are the code and a flag, which if set to true
542             # will cause the full name to be uppercased
543              
544             sub full_name
545             {
546 3     3 1 7 my $sub_country = shift;
547 3         9 my ($code,$uc_name) = @_;
548              
549 3 50       8 unless ( $sub_country->has_sub_countries )
550             {
551             # this country has no sub countries
552             # return;
553             }
554              
555 3         9 $code = _clean($code);
556 3         9 $code = uc($code);
557              
558             my $full_name =
559 3         10 $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_code_keyed}{$code};
560 3 100       9 if ( $uc_name )
561             {
562 1         4 $full_name = uc($full_name);
563             }
564              
565 3 100       8 if ( $full_name )
566             {
567 2         11 return($full_name);
568             }
569             else
570             {
571 1         6 return('unknown');
572             }
573             }
574              
575             #-------------------------------------------------------------------------------
576             # Given the alpha-2 ISO 3166-2 code for a sub country, return the level,
577             # being one of state, province, overseas territory, city, council etc
578             sub level
579             {
580 1     1 1 3 my $sub_country = shift;
581 1         2 my ($code) = @_;
582              
583 1         4 $code = _clean($code);
584              
585 1         4 my $level = $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{$code}{_level};
586              
587 1 50       5 if ( $level )
588             {
589 1         5 return($level);
590             }
591             else
592             {
593 0         0 return('unknown');
594             }
595             }
596             #-------------------------------------------------------------------------------
597             # Given a sub country object, return a hash of all the levels and their totals
598             # Such as Australia: State => 6, Territory => 2
599              
600             sub levels
601             {
602 0     0 0 0 my $sub_country = shift;
603            
604 0         0 return( %{ $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_levels} });
  0         0  
605              
606             }
607              
608             #-------------------------------------------------------------------------------
609             # Returns 1 if the current country has sub countries. otherwise 0.
610              
611             sub has_sub_countries
612             {
613 13     13 1 18 my $sub_country = shift;
614 13 50       38 if ( $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_code_keyed} )
615             {
616 13         40 return(1);
617             }
618             else
619             {
620 0         0 return(0);
621             }
622             }
623             #-------------------------------------------------------------------------------
624             # Returns a hash of code/full name pairs, keyed by sub country code.
625              
626             sub code_full_name_hash
627             {
628 3     3 1 292 my $sub_country = shift;
629 3 50       9 if ( $sub_country->has_sub_countries )
630             {
631 3         7 return( %{ $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_code_keyed} } );
  3         24  
632             }
633             else
634             {
635 0         0 return(undef);
636             }
637             }
638             #-------------------------------------------------------------------------------
639             # Returns a hash of name/code pairs, keyed by sub country name.
640              
641             sub full_name_code_hash
642             {
643 5     5 1 7 my $sub_country = shift;
644 5 50       11 if ( $sub_country->has_sub_countries )
645             {
646 5         7 return( %{ $Locale::SubCountry::subcountry{$sub_country->{_country_code}}{_full_name_keyed} } );
  5         37  
647             }
648             else
649             {
650 0         0 return(undef);
651             }
652             }
653             #-------------------------------------------------------------------------------
654             # Returns sorted array of all sub country full names for the current country
655              
656             sub all_full_names
657             {
658 2     2 1 288 my $sub_country = shift;
659 2 50       6 if ( $sub_country->full_name_code_hash )
660             {
661 2         5 my %all_full_names = $sub_country->full_name_code_hash;
662 2 50       10 if ( %all_full_names )
663             {
664 2         20 return( sort keys %all_full_names );
665             }
666             }
667             else
668             {
669 0         0 return(undef);
670             }
671             }
672             #-------------------------------------------------------------------------------
673             # Returns array of all sub country alpha-2 ISO 3166-2 codes for the current country
674              
675             sub all_codes
676             {
677 1     1 1 307 my $sub_country = shift;
678              
679 1 50       4 if ( $sub_country->code_full_name_hash )
680             {
681 1         4 my %all_codes = $sub_country->code_full_name_hash;
682 1         13 return( sort keys %all_codes );
683             }
684             else
685             {
686 0         0 return(undef);
687             }
688             }
689              
690             #-------------------------------------------------------------------------------
691             sub _clean
692             {
693 6     6   12 my ($input_string) = @_;
694              
695 6 100       27 if ( $input_string =~ /[\. ]/ )
696             {
697             # remove dots
698 3         12 $input_string =~ s/\.//go;
699              
700             # remove repeating spaces
701 3         6 $input_string =~ s/ +/ /go;
702              
703             # remove any remaining leading or trailing space
704 3         6 $input_string =~ s/^ //;
705 3         10 $input_string =~ s/ $//;
706             }
707              
708 6         14 return($input_string);
709             }
710              
711             return(1);