如何从关键字搜索中返回最短的代码段?

时间:2016-02-19 20:14:11

标签: javascript

我有以下任务要解决:

  

给出包含字母数字字词和搜索短语的内容页面   在N个单词中,编写一个将返回最短片段的算法   包含任何顺序的所有N个单词的内容。

这是我到目前为止所拥有的。我把页面上的文字变成了没有标点符号的数组:

var allText = $('#all-text').text();
var punctuationless = allText.replace(/[^A-Za-z0-9_]/g," ").toLowerCase();
var lessSpaces = punctuationless.replace(/\s{2,}/g," ");
var allTextArray = lessSpaces.split(" ");
var keywords = [];

我想我可能会使用.filter方法,但我不确定如何比较两个数组。

allTextArray.filter(keywords)
//find the indexes of the matches to the keywords
//compare how far apart the indexes are to each other and return the shortest length

2 个答案:

答案 0 :(得分:4)

因此,如果我理解OP,列出一些示例,如果页面文本是:

One for the money,
two for the show.
  • 搜索字词"One", "money"应生成"One for the money"
  • 搜索字词"One","two","for"应生成"One for the money, two"
  • 搜索字词"for","show"应生成"for the show"

    • ...但 for the money, two for the show

我添加了最后一点,因为这样的功能会增加很多复杂性,因为它现在必须找到所有组合中尺寸最小的搜索项组合。

我为此做了 a jsfiddle solution ,但我不会声称这是最有效的答案(因为已经很晚了,我的部分心思可能已经上床了)

基本上,它是一个迭代和扫描提前解决方案,这可能是一个人如何用他们的眼球做到这一点:

  1. 传递搜索文本并构建每个关键字及其索引的每次出现的数组。
  2. 确保数组的顺序基于关键字在文本中出现的顺序。
  3. 从(几乎)有序数组中的每个条目开始并向右扫描,直到找到每个关键字至少出现一次 - 此时我们看到它是否是我们到目前为止获得的最小片段。
  4. 毕竟说完了,所有可能的片段包括所有关键字都是检查。

    重要的是要注意我创建的解决方案不区分大小写,它匹配单词的部分,而不是整个单词,OP意味着不区分大小写和整个单词匹配。

    不区分大小写的策略(将所有输入文本转换为小写)和完整的单词匹配(剥去标点和额外空格的文本,然后拆分成数组)应该很容易适用于解决方案,特别是因为{{1} }对字符串和数组的工作方式相同。

    indexOf

    有关详细信息,请参阅 jsfiddle

答案 1 :(得分:2)

此解决方案使用两个数组q数组作为所需单词的排序列表及其位置:

[
    {
        "word": "bridge",
        "pos": 46
    },
    {
        "word": "city",
        "pos": 65
    },
    {
        "word": "bridge",
        "pos": 155
    },
    ...
]

qq数组,用于直接邻域中所有可能单词的组。它包括所需部件的开始和结束。该列表基本上被排序以获得最小长度并且被用于结果。

[
    {
        "start": 155,
        "end": 181
    },
    {
        "start": 177,
        "end": 220
    },
    ...
]

该算法会在原始文本中查找完整的字词,但只能应用toLowerCase



function getWords() {
    var text = document.getElementById('text').textContent,
        lowerText = text.toLowerCase(),
        wordsO = {},
        words = document.getElementById('words').value.split(' ').map(function (w) { wordsO[w.toLowerCase()] = true; return w.toLowerCase(); }),
        pattern = /\w+/g,
        execResult,
        result = [],
        q = [], qq = [], i, max;

    while ((execResult = pattern.exec(lowerText)) !== null) {
        wordsO[execResult[0]] && q.push({ word: execResult[0], pos: execResult.index });
    }

    for (i = 0; i < q.length - words.length + 1; i++) {
        max = words.reduce(function (r, w) {
            var j = i;
            while (j < q.length && q[j].word !== w) {
                j++;
            }
            return !~r || j === q.length ? -1 : j > r ? j : r;
        }, i);
        ~max && qq.push({ start: q[i].pos, end: q[max].pos + q[max].word.length });
    }

    qq.sort(function (a, b) { return a.end - a.start - b.end + b.start; });

    qq.every(function (a, _, aa) {
        return aa[0].end - aa[0].start === a.end - a.start && result.push(text.substring(a.start, a.end) + ' [' + a.start + ']');
    });

    document.getElementById('result').innerHTML = result.length && '<ul>' + result.map(function (a) { return '<li>' + a + '</li>'; }).join('') + '</ul>' || '### no match found ###';
}
&#13;
<form onsubmit="return false;">
    <textarea rows="5" cols="65" id="text">001 002 003 004 001 002 The George Washington Bridge in New York City is one of the oldest bridges ever constructed. It is now being remodeled because the bridge is a landmark. City officials say that the landmark bridge effort will create a lot of new jobs in the city.</textarea><br />
    <input type="text" id="words" value="Landmark City Bridge" /> <button onclick="getWords()">search</button>
</form>
Found search: <br />
<div id="result"></div>
&#13;
&#13;
&#13;