File Coverage

blib/lib/Regexp/Common/VATIN.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Regexp::Common::VATIN;
2              
3 1     1   50135 use strict;
  1         3  
  1         38  
4 1     1   5 use warnings FATAL => 'all';
  1         2  
  1         36  
5 1     1   1078 use utf8;
  1         10  
  1         5  
6 1     1   44 use Regexp::Common qw(pattern clean no_defaults);
  1         2  
  1         10  
7              
8             our $VERSION = 'v0.0.12'; # VERSION
9             # ABSTRACT: Patterns for matching EU VAT Identification Numbers
10              
11             my $uk_pattern = do {
12             my $multi_block = '[0-9]{3}[ ]?[0-9]{4}[ ]?[0-9]{2}[ ]?(?:[0-9]{3})?';
13             my $single_block = '(?:GD|HA)[0-9]{3}';
14             "(?:$multi_block|$single_block)";
15             };
16              
17             my %patterns = (
18             AT => 'U[0-9]{8}', # Austria
19             BE => '0[0-9]{9}', # Belgium
20             BG => '[0-9]{9,10}', # Bulgaria
21             CY => '[0-9]{8}[a-zA-Z]', # Cyprus
22             CZ => '[0-9]{8,10}', # Czech Republic
23             DE => '[0-9]{9}', # Germany
24             DK => '(?:[0-9]{2}[ ]?){3}[0-9]{2}', # Denmark
25             EE => '[0-9]{9}', # Estonia
26             EL => '[0-9]{9}', # Greece
27             GR => '[0-9]{9}', # Greece ISO-3166
28             ES => '[0-9a-zA-Z][0-9]{7}[0-9a-zA-Z]', # Spain
29             FI => '[0-9]{8}', # Finland
30             FR => '[0-9a-zA-Z]{2}[ ]?[0-9]{9}', # France
31             GB => $uk_pattern, # United Kingdom
32             HR => '[0-9]{11}', # Croatia
33             HU => '[0-9]{8}', # Hungary
34             IE => do { # Ireland
35             my $new_format = '[0-9]{7}[a-zA-Z]{1,2}';
36             my $old_format = '[0-9][0-9a-zA-Z+*][0-9]{5}[a-zA-Z]';
37             "(?:$new_format|$old_format)";
38             },
39             IM => $uk_pattern, # Isle of Man
40             IT => '[0-9]{11}', # Italy
41             LT => '(?:[0-9]{9}|[0-9]{12})', # Lithuania
42             LU => '[0-9]{8}', # Luxembourg
43             LV => '[0-9]{11}', # Latvia
44             MT => '[0-9]{8}', # Malta
45             NL => '[0-9]{9}[bB][0-9]{2}', # The Netherlands
46             PL => '[0-9]{10}', # Poland
47             PT => '[0-9]{9}', # Portugal
48             RO => '[0-9]{2,10}', # Romania
49             SE => '[0-9]{12}', # Sweden
50             SI => '[0-9]{8}', # Slovenia
51             SK => '[0-9]{10}' # Slovakia
52             );
53              
54             foreach my $alpha2 ( keys %patterns ) {
55             my $prefix = $alpha2 eq 'IM'
56             ? 'GB'
57             : $alpha2 eq 'GR'
58             ? 'EL'
59             : $alpha2;
60             pattern(
61             name => ['VATIN', $alpha2],
62             create => "$prefix$patterns{$alpha2}"
63             );
64             };
65             pattern(
66             name => [qw(VATIN any)],
67             create => do {
68             my $any = join(
69             '|',
70             map {
71             $_ . $patterns{$_}
72             } keys %patterns
73             );
74             "(?:$any)";
75             }
76             );
77              
78             1;
79             =encoding utf8
80              
81             =head1 NAME
82              
83             Regexp::Common::VATIN - Patterns for matching EU VAT Identification Numbers
84              
85             =head1 SYNOPSIS
86              
87             use feature qw(say);
88             use Regexp::Common qw(VATIN);
89             say "DE123456789" =~ $RE{VATIN}{DE}; # 1
90             say "DE123456789" =~ $RE{VATIN}{any}; # 1
91             say "LT123ABC" =~ $RE{VATIN}{LT}; # ""
92              
93             =head1 DESCRIPTION
94              
95             This module provides regular expression patterns to match any of the sanctioned
96             VATIN formats from the 27 nations levying a European Union value added tax. The
97             data found at http://ec.europa.eu/taxation_customs/vies/faq.html#item_11 is
98             used as the authoritative source of all patterns.
99              
100             =head1 JAVASCRIPT
101              
102             All patterns in this module are written to be compatible with JavaScript's
103             somewhat less-expressive regular expression standard. They can thus easily be
104             exported for use in a browser-facing web application:
105              
106             use JSON qw(encode_json);
107             my $patterns = encode_json($RE{VATIN});
108              
109             =head1 CAVEAT
110              
111             In keeping with the standard set by the core L modules, patterns
112             are neither anchored nor enclosed with word boundaries. Consider a malformed
113             VATIN, e.g.,
114              
115             my $vatin = "GB1234567890";
116              
117             According to the sanctioned patterns from the United Kingdom, the above VATIN is
118             malformed (one digit too many). And yet,
119              
120             say $vatin =~ $RE{VATIN}{GB}; # 1
121              
122             To test for an exact match, use start and end anchors:
123              
124             say $vatin =~ /^$RE{VATIN}{GB}$/; # ""
125              
126             =head1 SEE ALSO
127              
128             =over
129              
130             =item L
131              
132             For documentation of the interface this set of regular expressions uses.
133              
134             =item L
135              
136             Checks the official EU database for registered VATINs.
137              
138             =back
139              
140             =head1 AUTHOR
141              
142             Richard Simões C<< >>
143              
144             =head1 COPYRIGHT AND LICENSE
145              
146             Copyright © 2013 Richard Simões. This module is released under the terms of the
147             B and may be modified and/or redistributed under the same or any
148             compatible license.