'Parses a string, subbing color codes according to the stored
mapping.
Args:
string (str): The string to parse.
strip_ansi (boolean, optional): Strip all found ansi markup.
xterm256 (boolean, optional): If actually using xterm256 or if
these values should be converted to 16-color ANSI.
mxp (boolean, optional): Parse MXP commands in string.
Returns:
string (str): The parsed string.'

def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False):

    if hasattr(string, '_raw_string'):
        if strip_ansi:
            return string.clean()
        else:
            return string.raw()
    if (not string):
        return ''
    global _PARSE_CACHE
    cachekey = ('%s-%s-%s-%s' % (string, strip_ansi, xterm256, mxp))
    if (cachekey in _PARSE_CACHE):
        return _PARSE_CACHE[cachekey]
    string = self.brightbg_sub.sub(self.sub_brightbg, string)
    def do_xterm256(part):
        return self.sub_xterm256(part, xterm256)
    in_string = utils.to_str(string)
    parsed_string = ''
    parts = (self.ansi_escapes.split(in_string) + ['    '])
    for (part, sep) in zip(parts[::2], parts[1::2]):
        pstring = self.xterm256_sub.sub(do_xterm256, part)
        pstring = self.ansi_sub.sub(self.sub_ansi, pstring)
        parsed_string += ('%s%s' % (pstring, sep[0].strip()))
    if (not mxp):
        parsed_string = self.strip_mxp(parsed_string)
    if strip_ansi:
        return self.strip_raw_codes(parsed_string)
    _PARSE_CACHE[cachekey] = parsed_string
    if (len(_PARSE_CACHE) > _PARSE_CACHE_SIZE):
        _PARSE_CACHE.popitem(last=False)
    return parsed_string
