Как подсвечивать часть текста? [Легкий]

103
11 февраля 2022, 18:20

Есть у меня пару функций, которые возвращают две строки

"Какие произведения писателей заставляются задуматься о великом?" --- Исходная строка "Какие произведение писателей заставляются о великом?" ---- Строка, которую вернула функция

Мне надо, чтобы в исходной строке подсвечивалось так

Какие произведения писателей заставляются задуматься о великом

Прошу помощи

UPD (дополнил):

javascript

var string1 = "Какие произведения писателей заставляются задуматься о великом?";
var string2 = "Какие произведение писателей заставляются о великом?";
var elem = document.querySelector("result");

html:

<p class="result"></p> <! -- Просто пустой абзац -->

UPD

Исходная строка может быть больше той, которая вернула функция, а может и не быть больше (ну вы поняли)

Answer 1

let string1 = "Какие произведения писателей заставляются задуматься о великом?"; 
let string2 = "Какие произведения писателей заставляются о великом?"; 
 
document.getElementById("result").innerHTML = textHighlight(string1, string2); 
 
function textHighlight(str1, str2) { 
  str1 = str1.split(" "); 
 
  let str = str1.map(subStr => { 
    if (str2.includes(subStr)) { 
      return `<span class="highlight">${subStr}</span>`; 
    } else { 
      return subStr; 
    } 
  }); 
  return str.join(" "); 
}
.highlight { 
  color: red; 
}
<p id="result"></p>

Answer 2

немного не в тему, но.
что-то вроде diff строк с применением Map

// -- 
const makeBold = (str) => `<b>${str}</b>`; 
// разделить строку на массив слов 
const split = (str) => str.split(' '); 
// создать Map<string, boolean> из массива строк  
const toMap = (arr) => new Map(Array.from(arr, str => [str, true])); 
// -- 
const compare = (a, b) => { 
    let aM = toMap(split(a)); 
    let bM = toMap(split(b)); 
    // -- 
    aM.forEach((val, key) => { bM.has(key) && bM.set(key, false); }); 
    bM.forEach((val, key) => { aM.has(key) && aM.set(key, false); }); 
    // -- 
    return [ 
        Array.from(aM, ([key, val]) => val ? makeBold(key) : key).join(' '), 
        Array.from(bM, ([key, val]) => val ? makeBold(key) : key).join(' '), 
    ]; 
}; 
document.body.insertAdjacentHTML('beforeend', compare('Какие произведения писателей заставляют задуматься о великом', 'Какие произведения писателей заставляют о великом').join('<br>')); 
document.body.insertAdjacentHTML('beforeend', '<hr>'); 
document.body.insertAdjacentHTML('beforeend', compare('Какие произведения писателей заставляют задуматься о великом', 'Какие произведения писател заставляют о великом').join('<br>'));

а там то же самое на TS

Answer 3

Последовательный поиск от последнего совпадения - это и логичнее, и (должно быть) быстрее проверки каждого слова через includes(word):

const str1 = 'Какие произведения писателей заставляют задуматься о великом?'; 
const str2 = 'Какие произведение писателей заставляют о великом?'; 
const elem = document.querySelector('.result');  
elem.innerHTML = wrapMatches(str1, str2, '<span class="green">');  
console.log(elem.innerHTML);  
 
function wrapMatches(strA, strB, wrapper='<b>') { 
  const [wordsA, wordsB] = [strA.split(/\s+/), strB.split(/\s+/)].sort( 
    (a, b) => b.length - a.length 
  );  
  const [wordsAlc, wordsBlc] = [wordsA, wordsB].map( 
    arr => arr.map(itm => itm.toLowerCase()) 
  );  
  const endTag = `</${wrapper.match(/^<([^\s>]+)/)[1]}>`,  
        len = wordsA.length,  
        result = [];  
  let open = false;  
  for (let lastMatchIdx = 0, i = 0; i < len; ++i) { 
    let matchIdx = wordsBlc.indexOf(wordsAlc[i], lastMatchIdx);  
    if (matchIdx !== -1) { 
      if (!open) 
        open = !!result.push(wrapper);   // всегда вернет true: ="NOT(NOT(n)), n > 0" 
      lastMatchIdx = matchIdx;  
    } else if (open) { 
      open = !result.push(endTag);       // всегда вернет false: ="NOT(n), n > 0" 
    } 
    result.push(wordsA[i]);  
  } 
  if (open) 
    result.push(endTag); 
  return result.join(' ');  
}
p { font-family: sans-serif; } 
.green { font-weight: bold; color: #4d4; }
<p class="result"></p>

Второй аргумент indexOf это начальный индекс поиска - передаем индекс последнего найденного слова (lastMatchIdx), и получаем короткий проход по массиву: даже в пессимистичном сценарии, будет проверено length - lastMatchIdx элементов (только часть массива, а не всегда все его элементы от начала до конца).
Плюс, indexOf с массивами сам по себе работает быстрее includes.

Плюс, сохраняется последовательность, поэтому не будет неожиданных результатов при строках вида 'aaa bbb ccc bbb', 'aaa ccc bbb'.

READ ALSO
Убрать крестик в img

Убрать крестик в img

Если нет картинки то отображается крестикТак в EDGE происодит

89
Различие в #include &quot;mylib.h&quot; и #include &lt;mylib&gt;

Различие в #include "mylib.h" и #include <mylib>

Почему при объявлении стандартных библиотек компилятор принимает запись #include <syslib>, а стоит подключить свою библиотеку, например, вида...

127
Как в winapi убрать кнопки &quot;справка&quot; и &quot;файл&quot;?

Как в winapi убрать кнопки "справка" и "файл"?

Даже с стилем WS_POPUP остаются эти мерзкие кнопки и заголовок с названием окна, мне нужно и то и другое убрать(желательно без использования WS_POPUP)

97