def cat_replace(m, cats):
    """Replaces categories with regular expressions that will match them.

    Args:
        m: The match object. It should have two groups, the first one a
            (possibly zero-length) string of digits (the number for a numbered
            category), and the second a string of word characters (the name of
            the category).
        cats: The dict of categories to use in replacement.

    Returns:
        If there is no number, a pattern that simply matches every item in the
        category. If there is a number, the pattern will additionally capture
        the match to a named group, 'nc' + n + '_' + c, where n is the number,
        and c is the name of the category. If the name of the category is not
        found in cats, the original string is returned.
    """
    n, c = m.groups()
    if c in cats:
        if not n:
            return '(' + '|'.join(cats[c]) + ')'
        return '(?P<nc{}_{}>{})'.format(n, c, '|'.join(sorted(cats[c],
                                                              key=len,
                                                              reverse=True)))
    return m.group(0)