def linkify(text, nofollow=True, target=None, filter_url=identity,
            filter_text=identity, skip_pre=False, parse_email=False):
    """Convert URL-like strings in an HTML fragment to links.

    linkify() converts strings that look like URLs or domain names in a
    blob of text that may be an HTML fragment to links, while preserving
    (a) links already in the string, (b) urls found in attributes, and
    (c) email addresses.

    If the nofollow argument is True (the default) then rel="nofollow"
    will be added to links created by linkify() as well as links already
    found in the text.

    The target argument will optionally add a target attribute with the
    given value to links created by linkify() as well as links already
    found in the text.

    linkify() uses up to two filters on each link. For links created by
    linkify(), the href attribute is passed through filter_url()
    and the text of the link is passed through filter_text(). For links
    already found in the document, the href attribute is passed through
    filter_url(), but the text is untouched.
    """
    text = force_unicode(text)

    if not text:
        return u''

    parser = html5lib.HTMLParser(tokenizer=HTMLSanitizer)

    forest = parser.parseFragment(text)

    if nofollow:
        rel = u'rel="nofollow"'
    else:
        rel = u''

    def replace_nodes(tree, new_frag, node):
        new_tree = parser.parseFragment(new_frag)
        for n in new_tree.childNodes:
            tree.insertBefore(n, node)
        tree.removeChild(node)

    def strip_wrapping_parentheses(fragment):
        """Strips wrapping parentheses.

        Returns a tuple of the following format::

            (string stripped from wrapping parentheses,
             count of stripped opening parentheses,
             count of stripped closing parentheses)
        """
        opening_parentheses = closing_parentheses = 0
        # Count consecutive opening parentheses
        # at the beginning of the fragment (string).
        for char in fragment:
            if char == '(':
                opening_parentheses += 1
            else:
                break

        if opening_parentheses:
            newer_frag = ''
            # Cut the consecutive opening brackets from the fragment.
            fragment = fragment[opening_parentheses:]
            # Reverse the fragment for easier detection of parentheses
            # inside the URL.
            reverse_fragment = fragment[::-1]
            skip = False
            for char in reverse_fragment:
                # Remove the closing parentheses if it has a matching
                # opening parentheses (they are balanced).
                if (char == ')' and
                        closing_parentheses < opening_parentheses and
                        not skip):
                    closing_parentheses += 1
                    continue
                # Do not remove ')' from the URL itself.
                elif char != ')':
                    skip = True
                newer_frag += char
            fragment = newer_frag[::-1]

        return fragment, opening_parentheses, closing_parentheses

    def linkify_nodes(tree, parse_text=True):
        for node in tree.childNodes:
            if node.type == NODE_TEXT and parse_text:
                new_frag = node.toxml()
                if parse_email:
                    new_frag = re.sub(email_re, email_repl, new_frag)
                    if new_frag != node.toxml():
                        replace_nodes(tree, new_frag, node)
                        linkify_nodes(tree, False)
                        continue
                new_frag = re.sub(url_re, link_repl, new_frag)
                replace_nodes(tree, new_frag, node)
            elif node.name == 'a':
                if 'href' in node.attributes:
                    if nofollow:
                        node.attributes['rel'] = 'nofollow'
                    if target is not None:
                        node.attributes['target'] = target
                    href = node.attributes['href']
                    node.attributes['href'] = filter_url(href)
            elif skip_pre and node.name == 'pre':
                linkify_nodes(node, False)
            else:
                linkify_nodes(node)

    def email_repl(match):
        repl = u'<a href="mailto:%(mail)s">%(mail)s</a>'
        return repl % {'mail': match.group(0).replace('"', '&quot;')}

    def link_repl(match):
        url = match.group(0)
        open_brackets = close_brackets = 0
        if url.startswith('('):
            url, open_brackets, close_brackets = (
                    strip_wrapping_parentheses(url)
            )
        end = u''
        m = re.search(punct_re, url)
        if m:
            end = m.group(0)
            url = url[0:m.start()]
        if re.search(proto_re, url):
            href = url
        else:
            href = u''.join([u'http://', url])

        repl = u'%s<a href="%s" %s>%s</a>%s%s'

        attribs = [rel]
        if target is not None:
            attribs.append('target="%s"' % target)

        return repl % ('(' * open_brackets,
                       filter_url(href), ' '.join(attribs), filter_text(url),
                       end, ')' * close_brackets)

    linkify_nodes(forest)

    return _render(forest)
Convert URL-like strings in an HTML fragment to links.

    linkify() converts strings that look like URLs or domain names in a
    blob of text that may be an HTML fragment to links, while preserving
    (a) links already in the string, (b) urls found in attributes, and
    (c) email addresses.

    If the nofollow argument is True (the default) then rel="nofollow"
    will be added to links created by linkify() as well as links already
    found in the text.

    The target argument will optionally add a target attribute with the
    given value to links created by linkify() as well as links already
    found in the text.

    linkify() uses up to two filters on each link. For links created by
    linkify(), the href attribute is passed through filter_url()
    and the text of the link is passed through filter_text(). For links
    already found in the document, the href attribute is passed through
    filter_url(), but the text is untouched.
    
v2ex/babel/ext/bleach/__init__.py