#javascript #html #regex #search #full-text-search
Вопрос:
Задача: Учитывая поисковый запрос, состоящий из одного или нескольких слов, выделите каждое из слов, найденных в целевой строке из одного или нескольких слов. Обратите внимание, что поисковые слова могут отображаться в любом порядке и должны совпадать, даже если не все слова найдены в целевой строке.
Причина: Чтобы помочь пользователю визуализировать, почему целевая строка была сопоставлена с поисковым запросом, выделив совпадения.
Требование: Я также хочу, чтобы это соответствовало регистру без учета регистра.
Он должен обрабатывать простые случаи
Иглы: Foo bar
Сено: I pity the fool
Желаемый результат: Мне жаль фу л
Он должен соответствовать нескольким поисковым словам, разделенным строкой, в любом порядке в целевой строке
Иглы: Foo bar
Сено: I pity the bar fool
Желаемый результат: Мне жаль бар фу л
Он должен обрабатывать случаи, когда условия поиска могут конфликтовать друг с другом
Иглы: Barbeque bar
Сено: Quality barbeque grill
Желаемый результат: Качественный гриль для барбекю
Ответ №1:
Мое решение здесь основано на:
- Разделение поискового запроса на поисковые слова.
- Один за другим просматривая целевую строку, чтобы увидеть, существует ли в ней поисковое слово. Это делается путем разделения по поисковому слову.
- Те, у кого нечетный индекс, будут словом(ами), которые нужно выделить (если совпадения не найдено, результат будет иметь длину
1
, а у этого элемента будет индекс0
).
- Те, у кого нечетный индекс, будут словом(ами), которые нужно выделить (если совпадения не найдено, результат будет иметь длину
- Передача результатов на шаг 2, но только попытка выделить в целевой строке части, которые еще не выделены.
Лично я затем использую выходной массив непосредственно с Vue и позволяю ему выполнять задачи создания шаблонов, но включил здесь пример того, как он может выводить простой HTML для визуализации.
<script lang="js">
const splitHighlight = (arrayOfStrings, highlightWord) => {
// use () for capture and keeping the matched string, and `i` for case
// insensitive matching
const regex = new RegExp(`(${highlightWord})`, "i");
return arrayOfStrings
.map((s, i) => {
// if the index is odd then then this string is already highlighted,
// so don't try to highlight within the highlight
const isAlreadyHighlighted = i % 2 !== 0;
return isAlreadyHighlighted ? [s] : s.split(regex);
})
.flat();
};
const splitNeedlesInHay = (needlesStr, hay) => {
const needlesArray = needlesStr.trim().split(" ");
let hayArray = [hay];
needlesArray.forEach((n) => (hayArray = splitHighlight(hayArray, n)));
return hayArray;
};
const highlightNeedlesInHay = (needlesStr, hay) => {
const needlesInHay = splitNeedlesInHay(needlesStr, hay);
console.log(needlesInHay);
const transformHayArrayToHtmlReducer = (acc, curr, index) => {
return acc (index % 2 === 0 ? curr : `<b>${curr}</b>`);
};
return needlesInHay.reduce(transformHayArrayToHtmlReducer);
};
const result1 = highlightNeedlesInHay("Foo bar", "I pit the fool");
console.log(result1);
document.write(result1 "<br />");
const result2 = highlightNeedlesInHay("Foo bar", "I pit the bar fool");
console.log(result2);
document.write(result2 "<br />");
const result3 = highlightNeedlesInHay("Barbeque bar", "Quality barbeque grill");
console.log(result3);
document.write(result3 "<br />");
</script>