'Implements the internationalized string preparation algorithm from
RFC 4518. https://tools.ietf.org/html/rfc4518#section-2
:param string:
A unicode string to prepare
:return:
A prepared unicode string, ready for comparison'

def _ldap_string_prep(self, string):

    string = re.sub(u'[\xad\u1806\u034f\u180b-\u180d\ufe0f-\uff00\ufffc]+', u'', string)
    string = re.sub(u'[ DCTB \n\x0b\x0c\r\x85]', u'    ', string)
    if (sys.maxunicode == 65535):
        string = re.sub(u'\ud834[\udd73-\udd7a]|\udb40[\udc20-\udc7f]|\U000e0001', u'', string)
    else:
        string = re.sub(u'[\U0001d173-\U0001d17a\U000e0020-\U000e007f\U000e0001]', u'', string)
    string = re.sub(u'[\x00-\x08\x0e-\x1f\x7f-\x84\x86-\x9f\u06dd\u070f\u180e\u200c-\u200f\u202a-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb]+', u'', string)
    string = string.replace(u'\u200b', u'')
    string = re.sub(u'[\xa0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000]', u'    ', string)
    string = u''.join(map(stringprep.map_table_b2, string))
    string = unicodedata.normalize(u'NFKC', string)
    for char in string:
        if stringprep.in_table_a1(char):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    unassigned    code    points\n                                                                                '))
        if stringprep.in_table_c8(char):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    change    display    or\n                                                                                zzzzdeprecated    characters\n                                                                                '))
        if stringprep.in_table_c3(char):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    private    use    characters\n                                                                                '))
        if stringprep.in_table_c4(char):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    non-character    code    points\n                                                                                '))
        if stringprep.in_table_c5(char):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    surrogate    code    points\n                                                                                '))
        if (char == u'\ufffd'):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    objects    may    not    contain    the    replacement    character\n                                                                                '))
    has_r_and_al_cat = False
    has_l_cat = False
    for char in string:
        if stringprep.in_table_d1(char):
            has_r_and_al_cat = True
        elif stringprep.in_table_d2(char):
            has_l_cat = True
    if has_r_and_al_cat:
        first_is_r_and_al = stringprep.in_table_d1(string[0])
        last_is_r_and_al = stringprep.in_table_d1(string[(-1)])
        if (has_l_cat or (not first_is_r_and_al) or (not last_is_r_and_al)):
            raise ValueError(unwrap(u'\n                                                                                X.509    Name    object    contains    a    malformed    bidirectional\n                                                                                sequence\n                                                                                '))
    string = ((u'    ' + re.sub(u'    +', u'        ', string).strip()) + u'    ')
    return string
