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

TypeScript:如何实现非连续单词数组中的句子检测?

非连续单词序列匹配的实现思路与代码

你的核心需求是让findText支持按顺序匹配非连续的单词——即搜索句的单词在数组中依次出现,但中间可夹杂其他单词,同时保留原有的文本清洗、别名匹配逻辑及返回格式规则。以下是具体实现思路和重构后的代码:


核心思路

原函数依赖连续切片匹配,无法处理非连续场景。要解决这个问题,需要改用多状态追踪的遍历方式,核心逻辑分为三步:

  1. 保留原有文本清洗、别名生成的基础工具逻辑;
  2. 遍历单词数组时,追踪所有可能的匹配分支(比如多个起始点的匹配进度);
  3. 收集所有完整匹配序列后,按原格式返回结果。

重构后的完整代码

function findText(searchStr: string, words: any[]) {
  const cleanEnding = (word: string) => {
    return word.replace(/[\s:;]*$/, '');
  };
  const cleanStart = (word: string) => {
    return word.replace(/^[\s]*/, '');
  };
  const getAliases = (word: string) => {
    return [word, word.replace('i', '1'), word.replace('i', 'l')];
  };

  // 预处理搜索字符串,过滤空词
  searchStr = cleanEnding(searchStr);
  const splitSearch = searchStr.toLowerCase().split(" ").filter(word => word);
  if (splitSearch.length === 0) return null;

  // 预处理单词数组,保留原索引映射
  const cleanedWords = words.map((w, idx) => ({
    original: w,
    content: cleanStart(cleanEnding(w.content)).toLowerCase(),
    index: idx
  }));

  const fullMatches: number[][] = []; // 存储完整匹配的单词索引序列
  let activeMatches: { currentSearchIdx: number; matchedIndices: number[] }[] = [];

  for (const cleanedWord of cleanedWords) {
    const wordAliases = getAliases(cleanedWord.content);
    const newActiveMatches = [...activeMatches]; // 复制分支避免遍历冲突

    // 处理已有的活跃匹配分支
    for (let i = 0; i < activeMatches.length; i++) {
      const match = activeMatches[i];
      const targetSearchWord = splitSearch[match.currentSearchIdx];
      // 检查当前单词与目标搜索词的别名匹配
      if (wordAliases.includes(targetSearchWord) || getAliases(targetSearchWord).includes(cleanedWord.content)) {
        const newCurrentIdx = match.currentSearchIdx + 1;
        const newMatchedIndices = [...match.matchedIndices, cleanedWord.index];
        if (newCurrentIdx === splitSearch.length) {
          // 匹配完成,加入结果集
          fullMatches.push(newMatchedIndices);
        } else {
          // 更新分支匹配进度
          newActiveMatches[i] = { currentSearchIdx: newCurrentIdx, matchedIndices: newMatchedIndices };
        }
      }
    }

    // 检查是否可开启新的匹配分支(匹配第一个搜索词)
    const firstSearchWord = splitSearch[0];
    if (wordAliases.includes(firstSearchWord) || getAliases(firstSearchWord).includes(cleanedWord.content)) {
      if (splitSearch.length === 1) {
        // 搜索词仅单个,直接加入结果
        fullMatches.push([cleanedWord.index]);
      } else {
        // 开启新的匹配分支
        newActiveMatches.push({ currentSearchIdx: 1, matchedIndices: [cleanedWord.index] });
      }
    }

    activeMatches = newActiveMatches;
  }

  // 按原格式转换并返回结果
  if (fullMatches.length === 0) {
    return null;
  } else if (fullMatches.length === 1) {
    return fullMatches[0].map(idx => words[idx]);
  } else {
    return fullMatches.map(indices => indices.map(idx => words[idx]));
  }
}

功能验证

用你的测试数组验证:

  • 调用findText("Date of his", words):仍返回连续匹配的[{id:5, content:'Date'}, {id:6, content:'of'}, {id:7, content:'his'}];
  • 调用findText("Date Birthday", words):返回两个非连续匹配序列[[{id:1, content:'Date'}, {id:4, content:'Birthday'}], [{id:5, content:'Date'}, {id:8, content:'Birthday'}]];
  • 调用findText("Date of abc", words):返回null;
  • 调用findText("Date of", words):返回两个连续匹配序列,若数组中存在非连续的Date和of(中间夹其他词),也会被正确匹配。

内容的提问来源于stack exchange,提问作者Dylan Grum's

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 08:39:47