用<span>标记包裹子字符串(带嵌套)

时间:2017-02-08 14:03:47

标签: javascript regex search replace substring

我有一个用&lt;包装给定字符串部分的函数跨度&GT;标签取决于搜索子字符串。

E.g:

“然后是第一颗流星的夜晚。”

它将返回(并且没关系):

“然后是&lt; / span&gt; 的&lt; span&gt; &lt; span&gt;第一个&lt; / span&gt; 流星”。

“第一个”搜索字符串。如果我们尝试搜索字符串“rs of rs”(注意“rs”包含在“fi RS t”已经存在于我们的搜索字符串中)现在它给出了:

“然后来了&lt; span&gt;&lt; / span&gt; &lt; span&gt; fi&lt; span&gt; rs&lt; / span&gt; t&lt; / span&gt; 流星“。

但我们希望看到的是第一个结果:

“然后是&lt; / span&gt; &lt; span&gt; &lt; span&gt;第一个&lt; / span&gt; 流星”。

const markSubstring = (string, searchString) => {

    _.forEach(searchString.split(' '), function(value){
        if(value != '') {
            let regEx = new RegExp('(' + value + ')', "ig");
            string = string.replace(regEx, '<span>$1</span>');
        }
    });

    return _.map(string.split(/(<span>.*?<\/span>)/), (item, key) => {
        let val = item.split(/<span>(.*?)<\/span>/);
        if (val.length == 3) { return `<span>${val[1]}</span>` }
        return `${val}`;
    });
};

console.log(markSubstring('Then came the night of the first falling star.', 'first of'));
console.log('---------');
console.log(markSubstring('Then came the night of the first falling star.', 'first of rs'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

修改函数以获得预期结果的最佳方法是什么?

更新

给定字符串:然后是第一颗流星的夜晚。

一些搜索查询及其预期结果:

  

来了 - &gt;然后(来了)第一颗流星的夜晚。

     

首先出现 - &gt;然后(来了)(第一个)流星的夜晚。

     

am ig first - &gt;然后c(am)e(第一)流星的n(ig)ht。

     

第一个rs - &gt;然后是(第一个)坠落之星的夜晚。

     

first rs am - &gt;然后c(am)e(第一个)流星的夜晚。

因此我们将搜索字符串除以空格,并尝试在给定字符串中找到每个“子搜索查询”。

new RegExp('(' + value + ')', "ig");我们有一个&lt;跨度&GT;搜索嵌套时显示为字符串中的文本(不仅仅是它具有的样式)。因此,我认为最好的选择是在单词(或其部分已经突出显示)时将其放入。

1 个答案:

答案 0 :(得分:2)

修改

好的,我添加了以下逻辑来完善它。

  1. 按长度对所有搜索词进行排序,以便首先搜索最长的词。这样一来,如果搜索的是较短的单词,但是已经包含了较长的单词(已用<span>包裹),我们就知道不会插入另一个单词。
  2. 我们从字符串中拆分每个单词并确保它还没有用<span>
  3. 包裹

    你可以通过确保每个单词都是一个完整的单词而不是另一个单词的一部分来修复它。

    例如,如果我们使用正则表达式模式:/(^|\s)(first)(\s|$)/gi 我们确保单词first后面必须跟一个空格,一个字符串的开头或结尾。因此,在这种情况下,单词rs不能被视为单词。

    看到它的实际效果:

    const markSubstring = (string, searchString) => {
        var searchStrings = searchString.split(' ').sort(function(a, b){return b.length - a.length;});
        
        _.forEach(searchStrings, function(value){
            if(value != '') {
                let regEx = new RegExp('(' + value + ')', "ig");
                let validationRegEx = new RegExp('<span>.*?(' + value + ').*?<\/span>', "ig");
                var words = [];
                _.forEach(string.split(' '), function(word) {
                  if (!word.match(validationRegEx)) {
                    word = word.replace(regEx, '<span>$1</span>');
                  }
                  words.push(word);
                })          
                string = words.join(' ');
            }
        });
    
        return _.map(string.split(/(<span>.*?<\/span>)/), (item, key) => {
            let val = item.split(/<span>(.*?)<\/span>/);
            if (val.length == 3) { return `<span>${val[1]}</span>` }
            return `${val}`;
        });
    };
    
    console.log(markSubstring('Then came the night of the first falling star.', 'first of'));
    console.log('---------');
    console.log(markSubstring('Then came the night of the first falling star.', 'first of rs'));
    console.log('---------');
    console.log(markSubstring('Then came the night of the first falling star. rs is also a word.', 'first of rs'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>