import re


def filter_po_and_route_box_addresses(addresses_df):
    """
    Filters out PO and Route boxes from the DataFrame of unique addresses.

    :param addresses_df: DataFrame that contains unique addresses that has the columns 'id', 'Address', 'City', 'State',
    'ZIP Code', and 'data_id'.
    :type addresses_df: pandas.DataFrame

    :return: (DataFrame of addresses that do not contain PO and Route boxes, DataFrame of addresses that do contain PO
    and Route boxes)
    :rtype: tuple
    """
    # The regular expression that identifies the majority of PO Boxes and Route Boxes.
    regex = r'[p|P][\s]*[o|O][\s]*[b|B][\s]*[o|O][\s]*[x|X][\s]*[a-zA-Z0-9]*' \
            r'|' \
            r'\b[P|p]+(?:OST|ost|o|O)?\.?\s*[O|o|0]+(?:ffice|FFICE)?\.?\s*[B|b][O|o|0]?[X|x]+\.?\s+[#]?(?:\d+)*(?:\D+)*\b' \
            r'|' \
            r'\b(?:R\.?R\.?|R\.?T\.?|ROUTE)\b[^,].+\b(?:BO?X)\b'

    # Identify PO and Route Boxes in the 'Address' column case insensitively.
    print('Filtering out PO Boxes and Route Boxes from addresses...')
    post_route_bool = addresses_df['Address'].str.contains(regex, regex=True, flags=re.IGNORECASE)

    # Filter out PO and Route Box addresses into a separate DataFrame.
    po_and_route_box_df = addresses_df.loc[post_route_bool]
    no_box_addresses_df = addresses_df.loc[~post_route_bool]

    return no_box_addresses_df, po_and_route_box_df