Performs the reverse operation to .parse(), effectively returning
    markdown-like syntax given a normal text and its MessageEntity's.

    :param text: the text to be reconverted into markdown.
    :param entities: the MessageEntity's applied to the text.
    :return: a markdown-like text representing the combination of both inputs.

def unparse(text, entities, delimiters=None, url_fmt=None):
    """
    Performs the reverse operation to .parse(), effectively returning
    markdown-like syntax given a normal text and its MessageEntity's.

    :param text: the text to be reconverted into markdown.
    :param entities: the MessageEntity's applied to the text.
    :return: a markdown-like text representing the combination of both inputs.
    """
    if not text or not entities:
        return text

    if not delimiters:
        if delimiters is not None:
            return text
        delimiters = DEFAULT_DELIMITERS

    if url_fmt is None:
        url_fmt = DEFAULT_URL_FORMAT

    if isinstance(entities, TLObject):
        entities = (entities,)
    else:
        entities = tuple(sorted(entities, key=lambda e: e.offset, reverse=True))

    text = add_surrogate(text)
    delimiters = {v: k for k, v in delimiters.items()}
    for entity in entities:
        s = entity.offset
        e = entity.offset + entity.length
        delimiter = delimiters.get(type(entity), None)
        if delimiter:
            text = text[:s] + delimiter + text[s:e] + delimiter + text[e:]
        elif url_fmt:
            url = None
            if isinstance(entity, MessageEntityTextUrl):
                url = entity.url
            elif isinstance(entity, MessageEntityMentionName):
                url = 'tg://user?id={}'.format(entity.user_id)
            if url:
                # It's possible that entities are malformed and end up in the
                # middle of some character, like emoji, by using malformed
                # clients or bots. Try decoding the current one to check if
                # this is the case, and if it is, advance the entity.
                while e <= len(text):
                    try:
                        del_surrogate(text[s:e])
                        break
                    except UnicodeDecodeError:
                        e += 1
                else:
                    # Out of bounds, no luck going forward
                    while e > s:
                        try:
                            del_surrogate(text[s:e])
                            break
                        except UnicodeDecodeError:
                            e -= 1
                    else:
                        # No luck going backwards either, ignore entity
                        continue

                text = (
                    text[:s] +
                    add_surrogate(url_fmt.format(text[s:e], url)) +
                    text[e:]
                )

    return del_surrogate(text)