'Remove excluded tags from data set, return normalized genre list.
Filter all db tags, removing excluded tags supplied in opts.
Test for multiple tags resolving to same normalized form. Normalized
tags are flattened to alphanumeric ascii_text.
Args:
max_len: maximum length of normalized tag to fit within OS constraints
Return:
genre_tags_dict (dict): dict of filtered, normalized tags in data set'

def filter_genre_tags(self, max_len):

    def _format_tag_list(tags, indent=1, line_break=70, header='Tag    list'):
        def _next_tag(sorted_tags):
            for (i, tag) in enumerate(sorted_tags):
                if (i < (len(tags) - 1)):
                    (yield (tag + ',    '))
                else:
                    (yield tag)
        ans = ('%s%d    %s:\n' % (('    ' * indent), len(tags), header))
        ans += ('    ' * (indent + 1))
        out_str = ''
        sorted_tags = sorted(tags, key=sort_key)
        for tag in _next_tag(sorted_tags):
            out_str += tag
            if (len(out_str) >= line_break):
                ans += (out_str + '\n')
                out_str = ('    ' * (indent + 1))
        return (ans + out_str)
    def _normalize_tag(tag, max_len):
        '    Generate    an    XHTML-legal    anchor    string    from    tag.\n\n                                                Parse    tag    for    non-ascii,    convert    to    unicode    name.\n\n                                                Args:\n                                                    tags    (str):    tag    name    possible    containing    symbols\n                                                    max_len    (int):    maximum    length    of    tag\n\n                                                Return:\n                                                    normalized    (str):    unicode    names    substituted    for    non-ascii    chars,\n                                                        clipped    to    max_len\n                                                '
        normalized = massaged = re.sub('\\s', '', ascii_text(tag).lower())
        if re.search('\\W', normalized):
            normalized = ''
            for c in massaged:
                if re.search('\\W', c):
                    normalized += self.generate_unicode_name(c)
                else:
                    normalized += c
        shortened = shorten_components_to(max_len, [normalized])[0]
        return shortened
    normalized_tags = []
    friendly_tags = []
    excluded_tags = []
    all_genre_tags = []
    if (self.opts.genre_source_field == _('Tags')):
        all_genre_tags = self.db.all_tags()
    else:
        field_md = self.db.metadata_for_field(self.opts.genre_source_field)
        if ((field_md is None) or (not (field_md['datatype'] in ['enumeration', 'text']))):
            all_custom_fields = self.db.custom_field_keys()
            eligible_custom_fields = []
            for cf in all_custom_fields:
                if (self.db.metadata_for_field(cf)['datatype'] in ['enumeration', 'text']):
                    eligible_custom_fields.append(cf)
            self.opts.log.error("Custom    genre_source_field    must    be    either:\n    'Comma    separated    text,    like    tags,    shown    in    the    browser',\n    'Text,    column    shown    in    the    tag    browser',    or\n    'Text,    but    with    a    fixed    set    of    permitted    values'.")
            self.opts.log.error(('Eligible    custom    fields:    %s' % ',    '.join(eligible_custom_fields)))
            raise InvalidGenresSourceFieldException('invalid    custom    field    specified    for    genre_source_field')
        all_genre_tags = list(self.db.all_custom(self.db.field_metadata.key_to_label(self.opts.genre_source_field)))
    all_genre_tags.sort()
    for tag in all_genre_tags:
        if (tag in self.excluded_tags):
            excluded_tags.append(tag)
            continue
        try:
            if re.search(self.opts.exclude_genre, tag):
                excluded_tags.append(tag)
                continue
        except:
            self.opts.log.error((' DCTB filterDbTags():    malformed    --exclude-genre    regex    pattern:    %s' % self.opts.exclude_genre))
        if (tag == '    '):
            continue
        normalized_tags.append(_normalize_tag(tag, max_len))
        friendly_tags.append(tag)
    genre_tags_dict = dict(zip(friendly_tags, normalized_tags))
    normalized_set = set(normalized_tags)
    for normalized in normalized_set:
        if (normalized_tags.count(normalized) > 1):
            self.opts.log.warn(("                        Warning:    multiple    tags    resolving    to    genre    '%s':" % normalized))
            for key in genre_tags_dict:
                if (genre_tags_dict[key] == normalized):
                    self.opts.log.warn(('                            %s' % key))
    if self.opts.verbose:
        self.opts.log.info(('%s' % _format_tag_list(genre_tags_dict, header='enabled    genres')))
        self.opts.log.info(('%s' % _format_tag_list(excluded_tags, header='excluded    genres')))
    return genre_tags_dict
