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