2017-02-08 3 views
0

У меня есть функция, которая обертывает части данной строки тегом < span в зависимости от подстроки поиска.Wrap sub-string с тегом <span> (с вложением)

т.д .:

"Потом ночь первой падающей звезды."

он вернется (и это нормально):

"Потом продолжительность ночи <> из </SPAN>< SPAN> первый </SPAN> падающая звезда".

для "первый из" строка поиска. Если попытаться строку поиска «первый РС» (обратите внимание, что «RS» содержит в «Фи RS т», что уже существует в нашей строке поиска), и теперь он дает:

" Потом ночь < SPAN> из </SPAN>< SPAN> фи < SPAN> RS </SPAN> т </SPAN> падающая звезда».

Но то, что мы хотим видеть это первый результат:

"Потом ночь < SPAN> из </SPAN> пролете <> первый </SPAN> падающая звезда".

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>

Каков наилучший способ изменить функцию, чтобы получить ожидаемый результат?

UPDATE

Учитывая строку: Потом ночь первой падающей звезды.

Некоторые поисковые запросы и их ожидаемые результаты:

пришел -> Тогда (пришла) в ночь первой падающей звезды.

пришел первым -> Затем (наступила) ночь (первая) падающая звезда.

am ig first -> Тогда c (am) e n (ig) ht (первой) падающей звезды.

first rs -> Затем наступила ночь (первая) падающая звезда.

first rs am -> Затем c (am) e ночь (первая) падающая звезда.

т.д.

Таким образом, мы делим строку поиска пробелами и попытаться найти каждую из этих «суб-поисковых запросов» в данной строке.

С new RegExp('(' + value + ')', "ig"); у нас есть один < span> отображается как текст в строке при поиске вложенности (а не только в стиле, который у него есть). Поэтому лучший вариант, я полагаю, не ставить его, когда слово (или его часть уже выделено).

ответ

2

Редактировать

OK Я добавил следующую логику, чтобы усовершенствовать его.

  1. Сортировка всех поисковых слов по длине, чтобы первое поисковое слово сначала искалось. Таким образом, если поиск более короткого слова выполняется, но оно уже содержится как часть более длинного (которое было обернуто <span>), мы знаем, что не вставляем другой диапазон.
  2. Разделим каждое слово из строки и убедитесь, что он еще не был обернут <span>

Вы можете это исправить, убедившись, что каждое слово является полное слово, а не часть другого слово.

Например, если мы будем использовать шаблон регулярного выражения: /(^|\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>

+0

Придумал в основном то же решением, но оно не работало, пока я не заметил, что я совершенно забыл о двойных обратных косых вещах – Benjamin

+0

Спасибо за быстрый ответ! Хорошо, он решает проблему вложенности, но теперь он работает только для полного слова (с пространством в конце, без запятых или точек). Я не очень хорошо разбираюсь в регулярном выражении. Как мы можем объединить эти два вида поведения, чтобы найти, например, просто «rs» в «bla bla first bla bla», а также «first rs» (правильный путь) в одной строке? – Max

+0

Итак, вы хотели бы выделить часть строки, если это слово еще не обернуто пробелом? –

Смежные вопросы