def filter_and_join_taxonomy(feat_table, taxonomy, num_string, denom_string):
    """Perform taxonomy searching and join with feature table.

    Parameters:
    -----------
        feat_table: pd.DataFrame of features x samples
        taxonomy: pd.DataFrame of features x [Taxon, ...]
        num_string: numerator string to search for in taxonomy
        denom_string: denominator string to search for in taxonomy

    Returns:
    --------
        num_df: pd.DataFrame of numerator features x samples
        denom_df: pd.DataFrame of denominator features x samples
    """
    feat_table_copy = feat_table.loc[:, ((feat_table != 0).any(axis=0))]
    taxonomy = taxonomy.copy()
    taxonomy = taxonomy[['Taxon']]
    taxonomy_joined_df = taxonomy.join(feat_table_copy, how='inner',
        rsuffix='_q')
    num_indices = taxonomy_joined_df['Taxon'].str.contains(num_string)
    denom_indices = taxonomy_joined_df['Taxon'].str.contains(denom_string)
    tax_num_df = taxonomy_joined_df.loc[num_indices]
    tax_denom_df = taxonomy_joined_df.loc[denom_indices]
    tax_num_df.drop(columns='Taxon', inplace=True)
    tax_denom_df.drop(columns='Taxon', inplace=True)
    if 'Taxon_q' in taxonomy_joined_df:
        tax_num_df.rename(columns={'Taxon_q': 'Taxon'}, inplace=True)
        tax_denom_df.rename(columns={'Taxon_q': 'Taxon'}, inplace=True)
    if tax_num_df.shape[0] == 0:
        if tax_denom_df.shape[0] == 0:
            raise ValueError(
                'No feature(s) found matching either numerator or denominator string!'
                )
        else:
            raise ValueError('No feature(s) found matching numerator string!')
    if tax_denom_df.shape[0] == 0:
        raise ValueError('No feature(s) found matching denominator string!')
    tax_num_df = tax_num_df.loc[:, ((tax_num_df != 0).any(axis=0))]
    tax_denom_df = tax_denom_df.loc[:, ((tax_denom_df != 0).any(axis=0))]
    samp_to_keep = set(tax_num_df.columns).intersection(set(tax_denom_df.
        columns))
    if not samp_to_keep:
        raise ValueError(
            'No samples contain both numerator and denominator features!')
    tax_num_df = tax_num_df[samp_to_keep]
    tax_denom_df = tax_denom_df[samp_to_keep]
    return tax_num_df, tax_denom_df
