NAME
    Business::DK::Postalcode - validation and listing of Danish postal codes

VERSION
    This documentation describes version 0.08

SYNOPSIS
        # basic validation of string
        use Business::DK::Postalcode qw(validate);

        if (validate($postalcode)) {
            print "We have a valid Danish postalcode\n";
        } else {
            warn "Not a valid Danish postalcode\n";
        }


        # basic validation of string, using less intrusive subroutine
        use Business::DK::Postalcode qw(validate_postalcode);

        if (validate_postalcode($postalcode)) {
            print "We have a valid Danish postal code\n";
        } else {
            warn "Not a valid Danish postal code\n";
        }


        # using the untainted return value
        use Business::DK::Postalcode qw(validate_postalcode);

        if (my $untainted = validate_postalcode($postalcode)) {
            print "We have a valid Danish postal code: $untainted\n";
        } else {
            warn "Not a valid Danish postal code\n";
        }


        # extracting a regex for validation of Danish postal codes
        use Business::DK::Postalcode qw(create_regex);

        my $regex_ref = ${create_regex()};

        if ($postalcode =~ m/$regex/) {
            print "We have a valid Danish postal code\n";
        } else {
            warn "Not a valid Danish postal code\n";
        }


        # All postal codes for use outside this module
        use Business::DK::Postalcode qw(get_all_postalcodes);

        my @postalcodes = @{get_all_postalcodes()};


        # All postal codes and data for use outside this module
        use Business::DK::Postalcode qw(get_all_data);

        my $postalcodes = get_all_data();

        foreach (@{postalcodes}) {
            printf
                'postal code: %s city: %s street/desc: %s company: %s province: %d country: %d', split /\t/, $_, 6;
        }

FEATURES
    *   Providing list of Danish postal codes and related area names

    *   Look up methods for Danish postal codes for web applications and the
        like

DESCRIPTION
    This distribution is not the original resource for the included data,
    but simply acts as a simple distribution for Perl use. The central
    source is monitored so this distribution can contain the newest data.
    The monitor script (postdanmark.pl) is included in the distribution.

    The data are converted for inclusion in this module. You can use
    different extraction subroutines depending on your needs:

    *   "get_all_data", to retrieve all data, data description below in
        "Data".

    *   "get_all_postalcodes", to retrieve all postal codes

    *   "get_all_cities", to retieve all cities

    *   "get_postalcode_from_city", to retrieve one or more postal codes
        from a city name

    *   "get_city_from_postalcode", to retieve a city name from a postal
        code

  Data
    Here follows a description of the included data, based on the
    description from the original source and the authors interpretation of
    the data, including details on the distribution of the data.

   city name
    A non-unique, case-sensitive representation of a city name in Danish.

   street/description
    This field is either a streetname or a description, is it only provided
    for a few special records.

   company name
    This field is only provided for a few special records.

   province
    This field is a bit special and it's use is expected to be related to
    distribution all entries inside Copenhagen are marked as 'False' in this
    column and 'True' for all entries outside Copenhagen - and this of
    course with exceptions. The data are included since they are a part of
    the original data.

   country
    Since the original source contains data on 3 different countries:

    *   Denmark

    *   Greenland

    *   Faroe Islands

    Only the data representing Denmark has been included in this
    distribtion, so this field is always containing a one.

    For access to the data on Greenland or Faroe Islands please refer to:
    Business::GL::Postalcode and Business::FO::Postalcode respectfully.

  Encoding
    The data distributed are in Danish for descriptions and names and these
    are encoded in UTF-8.

EXAMPLES
    A web application example is included in the examples directory
    following this distribution or available at
    <https://metacpan.org/pod/Business::DK::Postalcode>.

SUBROUTINES AND METHODS
  validate
    A simple validator for Danish postal codes.

    Takes a string representing a possible Danish postal code and returns
    either 1 or 0 indicating either validity or invalidity.

        my $rv = validate(2665);

        if ($rv == 1) {
            print "We have a valid Danish postal code\n";
        } ($rv == 0) {
            print "Not a valid Danish postal code\n";
        }

  validate_postalcode
    A less intrusive subroutine for import. Acts as a wrapper of "validate".

        my $rv = validate_postalcode(2300);

        if ($rv) {
            print "We have a valid Danish postal code\n";
        } else {
            print "Not a valid Danish postal code\n";
        }

  get_all_data
    Returns a reference to a a list of strings, separated by tab characters.
    See "Data" for a description of the fields.

        use Business::DK::Postalcode qw(get_all_data);

        my $postalcodes = get_all_data();

        foreach (@{postalcodes}) {
            printf
                'postalcode: %s city: %s street/desc: %s company: %s province: %d country: %d', split /\t/, $_, 6;
        }

  get_all_postalcodes
    Takes no parameters.

    Returns a reference to an array containing all valid Danish postal
    codes.

        use Business::DK::Postalcode qw(get_all_postalcodes);

        my $postalcodes = get_all_postalcodes;

        foreach my $postalcode (@{$postalcodes}) { ... }

  get_all_cities
    Takes no parameters.

    Returns a reference to an array containing all Danish city names having
    a postal code.

        use Business::DK::Postalcode qw(get_all_cities);

        my $cities = get_all_cities;

        foreach my $city (@{$cities}) { ... }

    Please note that this data source used in this distribution by no means
    is authorative when it comes to cities located in Denmark, it might have
    all cities listed, but unfortunately also other post distribution data.

  get_city_from_postalcode
    Takes a string representing a Danish postal code.

    Returns a single string representing the related city name or an empty
    string indicating nothing was found.

        use Business::DK::Postalcode qw(get_city_from_postalcode);

        my $zipcode = '2300';

        my $city = get_city_from_postalcode($zipcode);

        if ($city) {
            print "We found a city for $zipcode\n";
        } else {
            warn "No city found for $zipcode";
        }

  get_postalcode_from_city
    Takes a string representing a Danish city name.

    Returns a reference to an array containing zero or more postal codes
    related to that city name. Zero indicates nothing was found.

    Please note that city names are not unique, hence the possibility of a
    list of postal codes.

        use Business::DK::Postalcode qw(get_postalcode_from_city);

        my $city = 'København K';

        my $postalcodes = get_postalcode_from_city($city);

        if (scalar @{$postalcodes} == 1) {
            print "$city is unique\n";
        } elsif (scalar @{$postalcodes} > 1) {
            warn "$city is NOT unique\n";
        } else {
            die "$city not found\n";
        }

  create_regex
    This method returns a generated regular expression for validation of a
    string representing a possible Danish postal code.

        use Business::DK::Postalcode qw(create_regex);

        my $regex_ref = ${create_regex()};

        if ($postalcode =~ m/$regex/) {
            print "We have a valid Danish postalcode\n";
        } else {
            print "Not a valid Danish postalcode\n";
        }

PRIVATE SUBROUTINES AND METHODS
  _retrieve_cities
    Takes a reference to an array based on the DATA section and return a
    reference to an array containing only city names.

   _retrieve_postalcode
    Takes a reference to an array based on the DATA section and return a
    reference to an array containing only postal codes.

   _build_tree
    Internal method to assist "create_regex" in generating the regular
    expression.

    Takes a <https://metacpan.org/pod/Tree::Simple> object and a reference
    to an array of data elements.

DIAGNOSTICS
    There are not special diagnostics apart from the ones related to the
    different subroutines.

CONFIGURATION AND ENVIRONMENT
    This distribution requires no special configuration or environment.

DEPENDENCIES
    *   <https://metacpan.org/pod/Carp> (core)

    *   <https://metacpan.org/pod/Exporter> (core)

    *   <https://metacpan.org/pod/Tree::Simple>

    *   <https://metacpan.org/pod/Params::Validate>

  TEST
    Please note that the above list does not reflect requirements for:

    *   Additional components in this distribution, see lib/. Additional
        components list own requirements

    *   Test and build system, please see: Build.PL for details

    *   Requirements for scripts in the bin/ directory

    *   Requirements for examples in the examples/ directory

BUGS AND LIMITATIONS
    There are no known bugs at this time.

    The data source used in this distribution by no means is authorative
    when it comes to cities located in Denmark, it might have all cities
    listed, but unfortunately also other post distribution data.

BUG REPORTING
    Please report issues via CPAN RT:

    *   Web (RT):
        <http://rt.cpan.org/NoAuth/Bugs.html?Dist=Business-DK-Postalcode>

    *   Web (Github): <https://github.com/jonasbn/bdkpst/issues>

    *   Email (RT): bug-Business-DK-Postalcode@rt.cpan.org

INCOMPATIBILITIES
    There are no known incompatibilities at this time.

TEST AND QUALITY
  Perl::Critic
    This version of the code is complying with
    <https://metacpan.org/pod/Perl::Critic> a severity: 1

    The following policies have been disabled.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::Variables::ProhibitP
        ackageVars>

        Disabled locally using 'no critic' pragma.

        The module uses a package variable as a cache, this might not prove
        usefull in the long term, so when this is adressed and this might
        address this policy.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::Require
        ArgUnpacking>

        Disabled locally using 'no critic' pragma.

        This policy is violated when using
        <https://metacpan.org/pod/Params::Validate> at some point this will
        be investigated further, this might be an issue due to referral to
        @_.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::RegularExpressions::
        RequireLineBoundaryMatching>

        Disabled locally using 'no critic' pragma.

        This is disabled for some two basic regular expressions.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::RegularExpressions::
        RequireExtendedFormatting>

        Disabled locally using 'no critic' pragma.

        This is disabled for some two basic regular expressions.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::RegularExpressions::
        RequireDotMatchAnything>

        Disabled locally using 'no critic' pragma.

        This is disabled for some two basic regular expressions.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::ValuesAndExpressions
        ::ProhibitConstantPragma>

        Constants are good, - see the link below.

    *   <https://logiclab.jira.com/wiki/display/OPEN/Perl-Critic-Policy-Valu
        esAndExpressions-ProhibitConstantPragma>

    *   <https://metacpan.org/pod/Perl::Critic::Policy::Documentation::Requi
        rePodAtEnd>

        This one interfers with our DATA section, perhaps DATA should go
        before POD, well it is not important so I have disabled the policy.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::ControlStructures::P
        rohibitCStyleForLoops>

        This would require a re-write of part of the code. Currently I rely
        on use of the iterator in the for loop, so it would require
        significant changes.

    *   <https://metacpan.org/pod/Perl::Critic::Policy::Documentation::Requi
        rePodLinksIncludeText>

        Temporarily disabled, marked for follow-up

    Please see t/perlcriticrc for details.

  TEST COVERAGE
    Test coverage report is generated using
    <https://metacpan.org/pod/Devel::Cover> via
    <https://metacpan.org/pod/Module::Build>, for the version described in
    this documentation (See VERSION).

        ---------------------------- ------ ------ ------ ------ ------ ------ ------
        File                           stmt   bran   cond    sub    pod   time  total
        ---------------------------- ------ ------ ------ ------ ------ ------ ------
        ...Business/DK/Postalcode.pm  100.0  100.0    n/a  100.0  100.0   98.7  100.0
        ...Business/DK/Postalcode.pm  100.0  100.0    n/a  100.0  100.0    1.2  100.0
        Total                         100.0  100.0    n/a  100.0  100.0  100.0  100.0
        ---------------------------- ------ ------ ------ ------ ------ ------ ------

        $ ./Build testcover

SEE ALSO
    *   Main data source:
        <http://www.postdanmark.dk/da/Documents/Lister/postnummerfil-excel.x
        ls>

    *   Information resource on data source:
        <http://www.postdanmark.dk/cms/da-dk/eposthuset/postservices/aendrin
        ger_postnumre_1.htm>

    *   Alternative implementation:
        <https://metacpan.org/pod/Geo::Postcodes::DK>

    *   Alternative validation:
        <https://metacpan.org/module/Regexp::Common::zip#RE-zip-Denmark->

    *   Related complementary implementation:
        <https://metacpan.org/pod/Business::GL::Postalcode>

    *   Related complementary implementation:
        <https://metacpan.org/pod/Business::FO::Postalcode>

    *   Related implementation, same author:
        <https://metacpan.org/pod/Business::DK::CVR>

    *   Related implementation, same author:
        <https://metacpan.org/pod/Business::DK::CPR>

    *   Related implementation, same author:
        <https://metacpan.org/pod/Business::DK::FI>

    *   Related implementation, same author:
        <https://metacpan.org/pod/Business::DK::PO>

RESOURCES
    *   MetaCPAN: <https://metacpan.org/pod/Business::DK::Postalcode>

    *   Website: <http://logicLAB.jira.com/browse/BDKPST>

    *   Bugtracker:
        <http://rt.cpan.org/NoAuth/Bugs.html?Dist=Business-DK-Postalcode>

    *   Git repository: <https://github.com/jonasbn/bdkpst>

TODO
    Please see the project TODO file, or the bugtracker (RT), website or
    issues resource at Github.

AUTHOR
    Jonas B. Nielsen, (jonasbn) - "<jonasbn@cpan.org>"

MOTIVATION
    Back in 2006 I was working on a project where I needed to do some
    presentation and validation of Danish postal codes. I looked at
    <https://metacpan.org/pod/Regex::Common::Zip>

    The implementation at the time of writing looked as follows:

        Denmark     =>  "(?k:(?k:[1-9])(?k:[0-9])(?k:[0-9]{2}))",
        # Postal codes of the form: 'DDDD', with the first
        # digit representing the distribution region, the
        # second digit the distribution district. Postal
        # codes do not start with a zero. Postal codes
        # starting with '39' are in Greenland.

    This pattern holds some issues:

    *   Doing some fast math you can see that you will allow 9000 valid
        postal codes where the number should be about 1254

    *   0 is actually allowed for a set of postal codes used by the postal
        service in Denmark, in some situations these should perhaps be
        allowed as valid data

    *   Greenland specified as starting with '39' is not a part of Denmark,
        but should be under Greenland and the ISO code 'GL', see also:

        *   <https://metacpan.org/pod/Business::GL::Postalcode>

    So I decided to write a regular expression, which would be better than
    the one above, but I did not want to maintain it I wanted to write a
    piece of software, which could generate the pattern for me based on a
    finite data set.

COPYRIGHT
    Business-DK-Postalcode is (C) by Jonas B. Nielsen, (jonasbn) 2006-2014

LICENSE
    Business-DK-Postalcode and related is released under the Artistic
    License 2.0

    *   <http://www.opensource.org/licenses/Artistic-2.0>

