You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

存在2+ gram时移除对应1-gram并还原文本顺序的问题求助

实现方案

核心逻辑是先给所有n-gram绑定它在原文本中的位置区间,先标记所有被长度≥2的gram覆盖的单词位置,再过滤掉被覆盖的1-gram,最后按位置拼接即可,全程不会打乱原文本顺序。

  • 第一步:预处理原文本位置映射
    先把输入的原文本按空格切分成单词列表,给每个单词分配从0开始的连续整数索引,方便后续给每个gram计算覆盖范围。
    以你给出的输入为例,切分后索引映射为:
    0:I, 1:love, 2:ice, 3:cream, 4:and, 5:the, 6:second, 7:person
  • 第二步:给所有输出的gram计算位置覆盖区间
    遍历你当前函数输出的所有(gram文本, 标签)元组,对每个gram按空格切分成单词,匹配它在原单词列表里的连续起始、结束索引,记录成(gram文本, 标签, 起始索引, 结束索引)的结构。
    比如ice cream切分后是['ice','cream'],对应原列表索引2到3,覆盖区间就是[2,3];the second person对应索引5到7,覆盖区间是[5,7]。
  • 第三步:标记所有被长gram覆盖的单词位置
    新建一个空集合存被覆盖的索引,遍历所有gram,只要gram的单词长度≥2,就把它覆盖区间内的所有索引都加入这个集合。
    你的示例里最终被覆盖的索引集合是{2,3,5,6,7}。
  • 第四步:过滤无效1-gram
    再次遍历所有带位置信息的gram,保留规则:
    • 单词长度≥2的gram全部保留
    • 1-gram只有当它的索引不在「被覆盖索引集合」里时才保留
      按这个规则过滤你的示例数据,剩下的条目为:
      (I, None, 0,0), (love, 'B2',1,1), (ice cream, 'A1',2,3), (and, 'A1',4,4), (the second person, 'B2',5,7)
  • 第五步:按位置排序拼接文本
    把过滤后的所有条目按「起始索引」从小到大排序,依次取出每个条目的gram文本,用空格拼接,得到的结果就和原输入文本完全一致。
参考代码片段
def filter_ngrams(original_text: str, raw_ngram_list: list[tuple[str, str|None]]) -> str:
    # 1. 构建原文本单词列表
    words = original_text.split()
    word_len = len(words)
    # 2. 给每个gram匹配位置信息
    ngram_with_pos = []
    for gram_text, tag in raw_ngram_list:
        gram_words = gram_text.split()
        gram_seg_len = len(gram_words)
        # 滑动匹配连续子序列位置,避免重复单词匹配错位
        start_idx = None
        for i in range(word_len - gram_seg_len + 1):
            if words[i:i+gram_seg_len] == gram_words:
                start_idx = i
                break
        if start_idx is None:
            raise ValueError("gram不在原文本中")
        end_idx = start_idx + gram_seg_len - 1
        ngram_with_pos.append( (gram_text, tag, start_idx, end_idx, gram_seg_len) )
    # 3. 收集所有长度≥2的gram覆盖的单词索引
    covered_idx = set()
    for item in ngram_with_pos:
        _, _, s, e, seg_len = item
        if seg_len >=2:
            covered_idx.update(range(s, e+1))
    # 4. 过滤被覆盖的1-gram
    filtered = []
    for item in ngram_with_pos:
        gram_text, _, s, _, seg_len = item
        if seg_len >=2:
            filtered.append(item)
        else:
            if s not in covered_idx:
                filtered.append(item)
    # 5. 按原位置排序后拼接
    filtered.sort(key=lambda x:x[2])
    return " ".join([item[0] for item in filtered])

# 测试你的示例数据
raw_list = [('I', None), ('love', 'B2'), ('ice', 'A2'), ('ice cream', 'A1'), ('cream', 'A2'), ('and', 'A1'), ('the', 'A1'), ('the second person', 'B2'), ('second', 'B1'), ('person', 'A1')]
origin = "I love ice cream and the second person"
print(filter_ngrams(origin, raw_list))
# 输出结果和原输入完全一致:I love ice cream and the second person

要是原文本里有重复出现的单词,别直接拿单词值查索引,就用上面代码里的滑动窗口做连续子序列匹配,不会出现位置匹配错误的问题。

内容的提问来源于stack exchange,提问作者Alan Kashkash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:18:27