"""
pyap.source_US.data
~~~~~~~~~~~~~~~~~~~~

This module provides regular expression definitions required for
detecting Canada addresses.

The module is expected to always contain 'full_address' variable containing
all address parsing definitions.

:copyright: (c) 2015 by Vladimir Goncharov.
:license: MIT, see LICENSE for more details.
"""

import re

"""
Numerals from one to nine
Note: here and below we use syntax like '[Oo][Nn][Ee]'
instead of '(one)(?i)' to match 'One' or 'oNe' because
Python Regexps don't seem to support turning On/Off
case modes for subcapturing groups.
"""
zero_to_nine = r"""(?:
    [Zz][Ee][Rr][Oo]\s|[Oo][Nn][Ee]\s|[Tt][Ww][Oo]\s|
    [Tt][Hh][Rr][Ee][Ee]\s|[Ff][Oo][Uu][Rr]\s|
    [Ff][Ii][Vv][Ee]\s|[Ss][Ii][Xx]\s|
    [Ss][Ee][Vv][Ee][Nn]\s|[Ee][Ii][Gg][Hh][Tt]\s|
    [Nn][Ii][Nn][Ee]\s|[Tt][Ee][Nn]\s|
    [Ee][Ll][Ee][Vv][Ee][Nn]\s|
    [Tt][Ww][Ee][Ll][Vv][Ee]\s|
    [Tt][Hh][Ii][Rr][Tt][Ee][Ee][Nn]\s|
    [Ff][Oo][Uu][Rr][Tt][Ee][Ee][Nn]\s|
    [Ff][Ii][Ff][Tt][Ee][Ee][Nn]\s|
    [Ss][Ii][Xx][Tt][Ee][Ee][Nn]\s|
    [Ss][Ee][Vv][Ee][Nn][Tt][Ee][Ee][Nn]\s|
    [Ee][Ii][Gg][Hh][Tt][Ee][Ee][Nn]\s|
    [Nn][Ii][Nn][Ee][Tt][Ee][Ee][Nn]\s
    )
"""

# Numerals - 10, 20, 30 ... 90
ten_to_ninety = r"""(?:
    [Tt][Ee][Nn]\s|[Tt][Ww][Ee][Nn][Tt][Yy]\s|
    [Tt][Hh][Ii][Rr][Tt][Yy]\s|
    [Ff][Oo][Rr][Tt][Yy]\s|
    [Ff][Oo][Uu][Rr][Tt][Yy]\s|
    [Ff][Ii][Ff][Tt][Yy]\s|[Ss][Ii][Xx][Tt][Yy]\s|
    [Ss][Ee][Vv][Ee][Nn][Tt][Yy]\s|
    [Ee][Ii][Gg][Hh][Tt][Yy]\s|
    [Nn][Ii][Nn][Ee][Tt][Yy]\s
    )"""

# One hundred
hundred = r"""(?:
    [Hh][Uu][Nn][Dd][Rr][Ee][Dd]\s
    )"""

# One thousand
thousand = r"""(?:
    [Tt][Hh][Oo][Uu][Ss][Aa][Nn][Dd]\s
    )"""

"""
Regexp for matching street number.
Street number can be written 2 ways:
1) Using letters - "One thousand twenty two"
2) Using numbers
   a) - "1022"
   b) - "85-1190"
        "85 - 1190"
        "85th - 1190"
   c) - "85 1190"
"""
street_number = r"""
(?<![\.0-9])(?P<street_number>
    (?:
        [Aa][Nn][Dd]\s
        |
        {thousand}
        |
        {hundred}
        |
        {zero_to_nine}
        |
        {ten_to_ninety}
    ){from_to}
    |
    # 85th - 1190
    (?:\d{from_to}(?:th)?
        (?:\s?\-?\s?\d{from_to}(?:th)?)?\s
    )
    |
    # 45
    (?:\d{from_to}(?=[\s,]))
)
""".format(
    thousand=thousand,
    hundred=hundred,
    zero_to_nine=zero_to_nine,
    ten_to_ninety=ten_to_ninety,
    from_to="{1,5}",
)

"""
Regexp for matching street name.
In example below:
"Hoover Boulevard": "Hoover" is a street name
"""
street_name = r"(?P<street_name>\w[\w0-9\'\-\s\.]{0,30}?)"

post_direction = r"""
(?P<post_direction>
    (?:
        # English
        [Nn][Oo][Rr][Tt][Hh]{d}|
        [Ss][Oo][Uu][Tt][Hh]{d}|
        [Ee][Aa][Ss][Tt]{d}|
        [Ww][Ee][Ss][Tt]{d}|
        [Nn][Oo][Rr][Tt][Hh][Ee][Aa][Ss][Tt]{d}|
        [Nn][Oo][Rr][Tt][Hh][Ww][Ee][Ss][Tt]{d}|
        [Ss][Oo][Uu][Tt][Hh][Ee][Aa][Ss][Tt]{d}|
        [Ss][Oo][Uu][Tt][Hh][Ww][Ee][Ss][Tt]{d}|
        # French
        [Ee][Ss][Tt]{d}|
        [Nn][Oo][Rr][Dd]{d}|
        [Nn][Oo][Rr][Dd]\-[Ee][Ss][Tt]{d}|
        [Nn][Oo][Rr][Dd]\-[Oo][Uu][Ee][Ss][Tt]{d}|
        [Ss][Uu][Dd]{d}|
        [Ss][Uu][Dd]\-[Ee][Ss][Tt]{d}|
        [Ss][Uu][Dd]\-[Oo][Uu][Ee][Ss][Tt]{d}|
        [Oo][Uu][Ee][Ss][Tt]{d}
    )
    |
    (?:
        # English
        NW{d}|NE{d}|SW{d}|SE{d}|
        # French (missing above)
        NO{d}|SO{d}
    )
    |
    (?:
        # English
        N\.?\s?|S\.?\s?|E\.?\s?|W\.?\s?|
        # French (missing above)
        O\.?\s?
    )
)
""".format(d=r"[\s,]")

# Regexp for matching street type
# According to
# https://www.canadapost.ca/tools/pg/manual/PGaddress-e.asp#1385939
street_type = r"""
(?P<street_type>
    [Aa][Bb][Bb][Ee][Yy]{div}|
    [Aa][Cc][Rr][Ee][Ss]{div}|
    [Aa][Ll][Ll][Éé][Ee]{div}|
    [Aa][Ll][Ll][Ee][Yy]{div}|
    [Aa][Uu][Tt][Oo][Rr][Oo][Uu][Tt][Ee]{div}|[Aa][Uu][Tt]{div}|
    [Aa][Vv][Ee][Nn][Uu][Ee]{div}|[Aa][Vv][Ee]?{div}|
    [Bb][Aa][Yy]{div}|
    [Bb][Ee][Aa][Cc][Hh]{div}|
    [Bb][Ee][Nn][Dd]{div}|
    [Bb][Oo][Uu][Ll][Ee][Vv][Aa][Er][Dd]{div}|[Bb][Ll][Vv][Dd]{div}|[Bb][Oo][Uu][Ll]{div}|
    # Broadway
    [Bb][Rr][Oo][Aa][Dd][Ww][Aa][Yy]{div}|
    [Bb][Yy]\-?[Pp][Aa][Ss][Ss]{div}|
    [Bb][Yy][Ww][Aa][Yy]{div}|
    [Cc][Aa][Mm][Pp][Uu][Ss]{div}|
    [Cc][Aa][Pp][Ee]{div}|
    [Cc][Aa][Rr][Rr][EéÉ]{div}|[Cc][Aa][Rr]{div}|
    [Cc][Aa][Rr][Rr][Ee][Ff][Oo][Uu][Rr]{div}|[Cc][Aa][Rr][Re][Ee][Ff]{div}|
    [Cc][Ee][Nn][Tt][Rr][Ee]{div}|[Cc][Tt][Rr]{div}|
    [Cc][Ee][Rr][Cc][Ll][Ee]{div}|
    [Cc][Hh][Aa][Ss][Ee]{div}|
    [Cc][Hh][Ee][Mm][Ii][Nn]{div}|[Cc][Hh]{div}|
    [Cc][Ii][Rr][Cc][Ll][Ee]{div}|[Cc][Ii][Rr]{div}|
    [Cc][Ii][Rr][Cc][Uu][Ii][Tt]{div}|[Cc][Ii][Rr][Cc][Tt]{div}|
    [Cc][Ll][Oo][Ss][Ee]{div}|
    [Cc][Oo][Mm][Mm][Oo][Nn]{div}|
    [Cc][Oo][Nn][Cc][Ee][Ss][Ss][Ii][Oo][Nn]{div}|[Cc][Oo][Nn][Cc]{div}|
    [Cc][Oo][Rr][Nn][Ee][Rr][Ss]{div}|
    [Cc][Ôô][Tt][Ee]{div}|
    [Cc][Oo][Uu][Rr][Ss]{div}|
    [Cc][Oo][Uu][Rr]{div}|
    [Cc][Oo][Uu][Rr][Tt]{div}|[Cc][Rr][Tt]{div}|
    [Cc][Oo][Vv][Ee]{div}|
    [Cc][Rr][Ee][Ss][Cc][Ee][Nn][Tt]{div}|[Cc][Rr][Ee][Ss]{div}|
    [Cc][Rr][Oo][Ii][Ss][Ss][Aa][Nn][Tt]{div}|[Cc][Rr][Oo][Ii][Ss]{div}|
    [Cc][Rr][Oo][Ss][Ss][Ii][Nn][Gg]{div}|[Cc][Rr][Oo][Ss][Ss]{div}|
    [Cc][Uu][Ll]\-[Dd][Ee]\-[Ss][Aa][Cc]{div}|[Cc][Dd][Ss]{div}|
    [Dd][Aa][Ll][Ee]{div}|
    [Dd][Ee][Ll][Ll]{div}|
    [Dd][Ii][Vv][Ee][Rr][Ss][Ii][Oo][Nn]{div}|[Dd][Ii][Vv][Ee][Rr][Ss]{div}|
    [Dd][Oo][Ww][Nn][Ss]{div}|
    [Dd][Rr][Ii][Vv][Ee]{div}|[Dd][Rr]{div}|
    [Ée][Cc][Hh][Aa][Nn][Gg][Ee][Uu][Rr]{div}|[Ée][Cc][Hh]{div}|
    [Ee][Nn][Dd]{div}|
    [Ee][Ss][Pp][Ll][Aa][Nn][Aa][Dd][Ee]{div}|[Ee][Ss][Pp][Ll]{div}|
    [Ee][Ss][Tt][Aa][Tt][Ee][Ss]?{div}|
    [Ee][Xx][Pp][Rr][Ee][Ss][Ss][Ww][Aa][Yy]{div}|[Ee][Xx][Pp][Yy]{div}|
    [Ee][Xx][Tt][Ee][Nn][Ss][Ii][Oo][Nn]{div}|[Ee][Xx][Tt][Ee][Nn]{div}|
    [Ff][Aa][Rr][Mm]{div}|
    [Ff][Ii][Ee][Ll][Dd]{div}|
    [Ff][Oo][Rr][Ee][Ss][Tt]{div}|
    [Ff][Rr][Ee][Ee][Ww][Aa][Yy]{div}|[Ff][Ww][Yy]{div}|
    [Ff][Rr][Oo][Nn][Tt]{div}|
    [Gg][Aa][Rr][Dd][Ee][Nn][Ss]{div}|[Gg][Dd][Nn][Ss]{div}|
    [Gg][Aa][Tt][Ee]{div}|
    [Gg][Ll][Aa][Dd][Ee]{div}|
    [Gg][Ll][Ee][Nn]{div}|
    [Gg][Rr][Ee][Ee][Nn]{div}|
    [Gg][Rr][Uo][Uu][Nn][Dd][Ss]{div}|[Gg][Rr][Nn][Dd][Ss]{div}|
    [Gg][Rr][Oo][Vv][Ee]{div}|
    [Hh][Aa][Rr][Bb][Oo][Uu][Rr]{div}|[Hh][Aa][Rr][Bb][Rr]{div}|
    [Hh][Ee][Aa][Tt][Hh]{div}|
    [Hh][Ee][Ii][Gg][Hh][Tt][Ss]{div}|[Hh][Tt][Ss]{div}|
    [Hh][Ii][Gg][Hh][Ll][Aa][Nn][Dd][Ss]{div}|[Hh][Gg][Hh][Ll][Dd][Sd]{div}|
    [Hh][Ii][Gg][Gh][Ww][Aa][Yy]{div}|[Hh][Ww][Yy]{div}|
    [Hh][Ii][Ll][Ll]{div}|
    [Hh][Oo][Ll][Ll][Oo][Ww]{div}|
    [Îi][Ll][Ee]{div}|
    [Ii][Mm][Pp][Aa][Ss][Ss][Ee]{div}|I[Mm][Pp]{div}|
    [Ii][Nn][Ll][Ee][Tt]{div}|
    [Ii][Ss][Ll][Aa][Nn][Dd]{div}|
    [Kk][Ee][Yy]{div}|
    [Kk][Nn][Oo][Ll][Ll]{div}|
    [Ll][Aa][Nn][Dd][Ii][Nn][Gg]{div}|[Ll][Aa][Nn][Dd][Nn][Gg]{div}|
    [Ll][Aa][Nn][Ee]{div}|
    [Ll][Ii][Mm][Ii][Tt][Ss]{div}|[Ll][Mm][Tt][Ss]{div}|
    [Ll][Ii][Nn][Ee]{div}|
    [Ll][Ii][Nn][Kk]{div}|
    [Ll][Oo][Oo][Kk][Oo][Uu][Tt]{div}|[Ll][Kk][Oo][Uu][Tt]{div}|
    [Mm][Aa][Ii][Nn][Ww][Aa][Yy]{div}|
    [Mm][Aa][Ll][Ll]{div}|
    [Mm][Aa][Nn][Oo][Rr]{div}|
    [Mm][Aa][Zz][Ee]{div}|
    [Mm][Ee][Aa][Dd][Oo][Ww]{div}|
    [Mm][Ee][Ww][Ss]{div}|
    [Mm][Oo][Nn][Tt][Éé][Ee]{div}|
    [Mm][Oo][Oo][Rr]{div}|
    [Mm][Oo][Uu][Nn][Tt][Aa][Ii][Nn]{div}|[Mm][Tt][Nn]{div}|
    [Mm][Oo][Uu][Nn][Tt]{div}|
    [Oo][Rr][Cc][Hh][Aa][Rr][Dd]{div}|[Oo][Rr][Cc][Hh]{div}|
    [Pp][Aa][Rr][Aa][Dd][Ee]{div}|
    [Pp][Aa][Rr][Cc]{div}|
    [Pp][Aa][Rr][Kk][Ww][Aa][Yy]{div}|[Pp][Kk][Yy]{div}|
    [Pp][Aa][Rr][Kk]{div}|[Pp][Kk]{div}|
    [Pp][Aa][Ss][Ss][Aa][Gg][Ee]{div}|[Pp][As][Ss][Ss]{div}|
    [Pp][Aa][Tt][Hh]{div}|
    [Pp][Aa][Tt][Hh][Ww][Aa][Yy]{div}|[Pp][Tt][Ww][Aa][Yy]{div}|
    [Pp][Ii][Nn][Ee][Ss]{div}|
    [Pp][Ll][Aa][Cc][Ee]{div}|[Pp][Ll]{div}|
    [Pp][Ll][Aa][Tt][Ee][Aa][Uu]{div}|[Pp][Ll][Aa][Tt]{div}|
    [Pp][Ll][Aa][Zz][Aa]{div}|
    [Pp][Oo][Ii][Nn][Tt][Ee]{div}|
    [Pp][Oo][Ii][Nn][Tt]{div}|[Pp][Tt]{div}|
    [Pp][Oo][Rr][Tt]{div}|
    [Pp][Rr][Ii][Vv][Aa][Tt][Ee]{div}|[Pp][Vv][Tt]{div}|
    [Pp][Rr][Oo][Mm][Ee][Nn][Aa][Dd][Ee]{div}|[Pp][Rr][Oo][Mm]{div}|
    [Qq][Uu][Aa][Ii]{div}|
    [Qq][Uu][Aa][Yy]{div}|
    [Rr][Aa][Mm][Pp]{div}|
    [Rr][Aa][Nn][Gg][Ee]{div}|[Rr][Gg]{div}|
    [Rr][Aa][Nn][Gg]{div}|
    [Rr][Ii][Dd][Gg][Ee]{div}|
    [Rr][Ii][Ss][Ee]{div}|
    [Rr][Oo][Aa][Dd]{div}|[Rr][Dd]{div}|
    [Rr][Oo][Nn][Dd]\-[Pp][Oo][Ii][Nn][Tt]{div}|[Rr][Dd][Pp][Tt]{div}|
    [Rr][Oo][Uu][Tt][Ee]{div}|[Rr][Tt][Ee]{div}|
    [Rr][Oo][Ww]{div}|
    [Rr][Uu][Ee][Ll][Ll][Ee]{div}|[Rr][Ll][Ee]{div}|
    [Rr][Uu][Ee]{div}|
    [Rr][Uu][Nn]{div}|
    [Ss][Ee][Nn][Tt][Ii][Ee][Rr]{div}|[Ss][Ee][Nn][Tt]{div}|
    # Street
    [Ss][Tt][Rr][Ee][Ee][Tt]{div}|[Ss][Tt](?![A-Za-z]){div}|
    # Square
    [Ss][Qq][Uu][Aa][Rr][Ee]{div}|[Ss][Qq]{div}|
    [Ss][Uu][Bb][Dd][Ii][Vv][Ii][Ss][Ii][Oo][Nn]{div}|[Ss][Uu][Bb][Dd][Ii][Vv]{div}|
    [Tt][Ee][Rr][Rr][Aa][Cc][Ee]{div}|[Tt][Ee][Re][Re]{div}|
    [Tt][Ee][Rr][Rr][Aa][Ss][Ss][Ee]{div}|[Tt][Ss][Ss][Es]{div}|
    [Tt][Hh][Ii][Cc][Kk][Ee][Tt]{div}|[Tt][Hh][Ii][Cc][Kk]{div}|
    [Tt][Oo][Ww][Ee][Rr][Ss]{div}|
    [Tt][Oo][Ww][Nn][Ll][Ii][Nn][Ee]{div}|[Tt][Ll][Ii][Nn][Ee]{div}|
    [Tt][Rr][Aa][Ii][Ll]{div}|
    [Tt][Uu][Rr][Nn][Aa][Bb][Oo][Uu][Tt]{div}|[Tt][Rr][Nn][Aa][Bb][Tt]{div}|
    [Vv][Aa][Ll][Ee]{div}|
    [Vv][Ii][Aa]{div}|
    [Vv][Ii][Ee][Ww]{div}|
    [Vv][Ii][Ll][Ll][Aa][Gg][Ee]{div}|[Vv][Ii][Ll][Ll][Gg][Ee]{div}|
    [Vv][Ii][Ll][Ll][Aa][Ss]{div}|
    [Vv][Ii][Ss][Tt][Aa]{div}|
    [Vv][Oo][Ii][Ee]{div}|
    [Ww][Aa][Ll][Lk]{div}|
    [Ww][Aa][Yy]{div}|
    [Ww][Hh][Aa][Rr][Ff]{div}|
    [Ww][Oo][Oo][Dd]{div}|
    [Ww][Yy][Nn][Dd]{div}
)
(?P<route_id>
    [\(\s\,]{route_symbols}
    [Rr][Oo][Uu][Tt][Ee]\s[A-Za-z0-9]+[\)\s\,]{route_symbols}
)?
""".format(div=r"[\.\s,]{0,2}", route_symbols="{0,3}")

floor = r"""
(?P<floor>
    (?:
    \d+[A-Za-z]{0,2}\.?\s[Ff][Ll][Oo][Oo][Rr]\s
    )
    |
    (?:
        [Ff][Ll][Oo][Oo][Rr]\s\d+[A-Za-z]{0,2}\s
    )
)
"""

building = rf"""
(?P<building_id>
    (?:
        (?:[Bb][Uu][Ii][Ll][Dd][Ii][Nn][Gg])
        |
        (?:[Bb][Ll][Dd][Gg])
    )
    \s
    (?:
        (?:
            [Aa][Nn][Dd]\s
            |
            {thousand}
            |
            {hundred}
            |
            {zero_to_nine}
            |
            {ten_to_ninety}
        ){{1,5}}
        |
        \d{{0,4}}[A-Za-z]?
    )
    \s ?
)  # end building_id
"""

occupancy = r"""
(?:
    (?:
        (?:
            #
            # English
            #
            # Suite
            [Ss][Uu][Ii][Tt][Ee]\s|[Ss][Tt][Ee]\.?\s
            |
            # Apartment
            [Aa][Pp][Tt]\.?\s|[Aa][Pp][Aa][Rr][Tt][Mm][Ee][Nn][Tt]\s
            |
            # Room
            [Rr][Oo][Oo][Mm]\s|[Rr][Mm]\.?\s
            |
            # Unit
            [Uu][Nn][Ii][Tt]\s
            |
            #
            # French
            #
            # Apartement
            [Aa][Pp][Aa][Rr][Tt][Ee][Mm][Ee][Nn][Tt]\s|A[Pp][Pp]\s
            |
            # Bureau
            [Bb][Uu][Rr][Ee][Aa][Uu]\s
            |
            # Unité
            [Uu][Nn][Ii][Tt][Éé]\s
        )
        (?:
            [A-Za-z\#\&\-\d]{1,7}
        )?
    )
    |
    (?:
        \#[0-9]{,3}[A-Za-z]{1}
    )
)\s?
"""

po_box = r"""
    (?P<postal_box>
        # English - PO Box 123
        (?:[Pp]\.?\s?[Oo]\.?\s[Bb][Oo][Xx]\s\d+)
        |
        # French - B.P. 123
        (?:[Bb]\.?\s[Pp]\.?\s\d+)
        |
        # C.P. 123
        (?:[Cc]\.?\s[Pp]\.?\s\d+)
        |
        # Case postale 123
        (?:[Cc]ase\s[Pp][Oo][Ss][Tt][Aa][Ll][Ee]\s\d+)
        |
        # C.P. 123
        (?:[Cc]\.[Pp]\.\s\d+)
    )
"""

"""
Define detection rules for a second type of address format (the French one)
"""
street_number_b = re.sub(r"<([a-z\s]+)>", r"<\1_b>", street_number)
street_name_b = re.sub(r"<([a-z\s]+)>", r"<\1_b>", street_name)
street_type_b = re.sub(r"<([a-z\s]+)>", r"<\1_b>", street_type)
po_box_b = re.sub(r"<([a-z\s]+)>", r"<\1_b>", po_box)
post_direction_b = re.sub(r"<([a-z\s*]+)>", r"<\1_b>", post_direction)

po_box_positive_lookahead = r"""
    (?=
        # English - PO Box 123
        (?:[Pp]\.?\s?[Oo]\.?\s[Bb][Oo][Xx]\s\d+)
        |
        # French - B.P. 123
        (?:[Bb]\.?\s[Pp]\.?\s\d+)
        |
        # C.P. 123
        (?:[Cc]\.?\s[Pp]\.?\s\d+)
        |
        # Case postale 123
        (?:[Cc]ase\s[Pp][Oo][Ss][Tt][Aa][Ll][Ee]\s\d+)
        |
        # C.P. 123
        (?:[Cc]\.[Pp]\.\s\d+)
        |
        (?:[\s\,])
    )
"""

full_street = r"""
(?:
    # Format commonly used in French
    (?P<full_street_b>

        {street_number_b}{div}
        {street_type_b}{div}
        ({street_name_b} {po_box_positive_lookahead})?\,?\s?
        {post_direction_b}?\,?\s?
        {po_box_b}?\,?\s?
    )
    |
    # Format commonly used in English
    (?P<full_street>

        {street_number}\,?\s?
        {street_name}?\,?\s?
        (?:(?<=[\s\,]){street_type})\,?\s?
        {post_direction}?\,?\s?
        {floor}?\,?\s?

        (?P<building_id>
            {building}
        )?\,?\s?

        (?P<occupancy>
            {occupancy}
        )?\,?\s?

        {po_box}?
    )
)""".format(
    street_number=street_number,
    street_number_b=street_number_b,
    street_name=street_name,
    street_name_b=street_name_b,
    street_type=street_type,
    street_type_b=street_type_b,
    post_direction=post_direction,
    post_direction_b=post_direction_b,
    floor=floor,
    building=building,
    occupancy=occupancy,
    po_box=po_box,
    po_box_b=po_box_b,
    po_box_positive_lookahead=po_box_positive_lookahead,
    div=r"[\s,]{1,2}",
)

# region1 here is actually a "province"
region1 = r"""
(?P<region1>
    (?:
        # province abbreviations (English)
        A\.?B\.?|B\.?C\.?|M\.?B\.?|N\.?B\.?|N\.?L\.?|
        N\.?T\.?|N\.?S\.?|N\.?U\.?|O\.?N\.?|P\.?E\.?|
        Q\.?C\.?|S\.?K\.?|Y\.?T\.?
    )
    |
    (?:
        # provinces full (English)
        [Aa][Ll][Bb][Ee][Rr][Tt][Aa]|
        [Bb][Rr][Ii][Tt][Ii][Ss][Hh]\s[Cc][Oo][Ll][Uu][Mm][Bb][Ii][Aa]|
        [Mm][Aa][Nn][Ii][Tt][Oo][Bb][Aa]|
        [Nn][Ee][Ww]\s[Bb][Rr][Uu][Nn][Ss][Ww][Ii][Cc][Kk]|
        [Nn][Ee][Ww][Ff][Oo][Uu][Nn][Dd][Ll][Aa][Nn][Dd]\s
        [Aa][Nn][Dd]\s[Ll][Aa][Bb][Rr][Aa][Dd][Oo][Rr]|
        [Nn][Ee][Ww][Ff][Oo][Uu][Nn][Dd][Ll][Aa][Nn][Dd]\s
        \&\s[Ll][Aa][Bb][Rr][Aa][Dd][Oo][Rr]|
        [Nn][Oo][Rr][Tt][Hh][Ww][Ee][Ss][Tt]\s
        [Tt][Ee][Rr][Rr][Ii][Tt][Oo][Rr][Ii][Ee][Ss]|
        [Nn][Oo][Vv][Aa]\s[Ss][Cc][Oo][Tt][Ii][Aa]|
        [Nn][Uu][Nn][Aa][Vv][Uu][Tt]|
        [Oo][Nn][Tt][Aa][Rr][Ii][Oo]|
        [Pp][Rr][Ii][Nn][Cc][Ee]\s[Ee][Dd][Ww][Aa][Rr][Dd]\s
        [Ii][Ss][Ll][Aa][Nn][Dd]|
        [Qq][Uu][Ee][Bb][Ee][Cc]|
        [Ss][Aa][Ss][Kk][Aa][Tt][Cc][Hh][Ee][Ww][Aa][Nn]|
        [Yy][Uu][Kk][Oo][Nn]|
        # provinces full (French)
        [Cc][Oo][Ll][Oo][Mm][Bb][Ii][Ee]\-
        [Bb][Rr][Ii][Tt][Aa][Nn]{1,2}[Ii][Qq][Eu][Ee]|
        [Nn][Oo][Uu][Vv][Ee][Aa][Uu]\-[Bb][Rr][Uu][Nn][Ss][Ww][Ii][Cc][Kk]|
        [Tt][Ee][Rr][Rr][Ee]\-[Nn][Ee][Uu][Vv][Ee]\-
        [Ee][Tt]\-[Ll][Aa][Bb][Rr][Aa][Dd][Oo][Rr]|
        [Tt][Ee][Rr][Rr][Ii][Tt][Oo][Ii][Rr][Ee][Ss]\s[Dd][Uu]\s
        [Nn][Oo][Rr][Dd]\-[Oo][Uu][Ee][Ss][Tt]|
        [Nn][Oo][Uu][Vv][Ee][Ll][Ll][Ee]\-[ÉéEe][Cc][Oo][Ss][Ss][Ee]|
        [ÎîIi][Ll][Ee]\-[Dd][Uu]\-[Pp][Rr][Ii][Nn][Cc][Ee]\-
        [ÉéEe][Dd][Oo][Uu][Aa][Rr][Dd]|
        [Qq][Uu][Éé][Bb][Ee][Cc]
    )
)
"""

city = r"""
(?P<city>
    (?<=[\, ])[A-z]{1}(?![0-9]) # city second char should not be number
    [\w\s\-\'\.]{2,20}?(?=[\, ])
)
"""

postal_code = r"""
(?P<postal_code>
    (?:
        [ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]\s?
        \d[ABCEGHJKLMNPRSTVWXYZ]\d
    )
)
"""

country = r"""
            (?:
                [Cc][Aa][Nn][Aa][Dd][Aa]
            )
            """

# define detection rules for postal code placed in different parts of address
postal_code_b = re.sub(r"<([a-z\s]+)>", r"<\1_b>", postal_code)
postal_code_c = re.sub(r"<([a-z\s]+)>", r"<\1_c>", postal_code)

full_address = r"""
                (?P<full_address>
                    {full_street} {div}
                    {city} {div}
                    (?:{postal_code_c} {div})?
                    \(?{region1}[\)\.]? {div}
                    (?:
                        (?:
                            {postal_code}? {div} {country}? 
                            (?:{div} {postal_code_b})?
                        )
                    )
                )
                """.format(
    full_street=full_street,
    div=r"[\, ]{,2}",
    city=city,
    region1=region1,
    country=country,
    postal_code=postal_code,
    postal_code_b=postal_code_b,
    postal_code_c=postal_code_c,
)
