import unicodedata


def len(s):
    """
    Calculates the length of a string. This function takes into account
    CJK and zero-width characters.

    .. note::

        The string passed to this function is expected to have been
        :attr:`normalized <normalize>`.

    Parameters
    ----------
    s: :class:`str`
        The string to calculate the length of.

    Returns
    -------
    :class:`int`
        The calculated length of the string.

    Examples
    --------

    .. code:: python3

        >>> len("oranges")
        7

        >>> len("\\x00")
        0

        >>> len("\u65E5\u672C\u8A9E")
        6

        >>> len("\\u0061\\u0301")  # \u0061\u0301
        2

        >>> len(normalize("\\u0061\\u0301"))  # \u00E1
        1
    """

    # NOTE: unicode characters 0001-0006, 0010-001A, 001C-001F appear
    #       to be replaced in WT by 263A-263B, 2665-2666, 2663, 2660,
    #       25BA, 25C4, 2195, 203C, 00B6, 00A7, 25AC, 21A8, 2191, 2193,
    #       2192, 221F, 2194, 25B2, and 25BC respectively.

    l = 0

    for c in s:
        # NOTE: unicode characters 0000-001F, and 007F-009F get special
        #       cased to zero-width
        if ord(c) <= 31 or 127 <= ord(c) <= 159:
            continue

        w = unicodedata.east_asian_width(c)

        if w in "FW":
            l += 2
        else:
            l += 1

    return l