Перекрывающиеся регулярные выражения совпадают с методом замены

Regex новичок здесь! Допустим, у меня есть два массива текста, и я ищу текст, который говорит.

let text = This is a cool story.
Я ищу эти фразы в тексте.

ArrBlue = ["cool story"] 
ArrGreen = ["This is a cool"] 

И я хочу выделить слова в массиве с соответствующим цветом. Таким образом, все слова в ArrBlue будут иметь синий текст, а ArrGreen - зеленый. Я создал два новых RegExp, как это..

let regexBlue = new RegExp(arrBlue.join('|'), "ig)  
let regexGreen = new RegExp(arrGreen.join('|'), "ig)

и затем я использую эти новые переменные, чтобы затем заменить текст, таким образом прикрепляя тег span к началу и концу сопоставленного выражения.

let newText = text.replace(regexBlue, "<span class='blue'>$&</span>")    
.replace(regexGreen, "<span class='green'>$&</span>")

Проблема, которую я имею, - я хочу, чтобы мой HTML выглядел так...

<span class="blue">This is a<span class="green" cool story </span> </span>

Но на самом деле я получаю

This is a <span class="green">cool story</span>

Вот мой быстрый фрагмент, чтобы лучше понять мою ситуацию.

let greenListArray = ["cool story"];
let blueListArray = ['This is a cool'];

$("#myform").submit(function(event){
   event.preventDefault();
   $('#results').html('');
   let text = $('textarea#textEntered').val();
   highlightText(text); 
});

function highlightText(text){

let regexGreen = new RegExp(greenListArray.join('[,!?.]?|'), "ig");
let regexBlue = new RegExp(blueListArray.join('[,!?.]?|') + "ig");

let newText = text.replace(regexGreen, "<span class='green'>$&</span>")
.replace(regexBlue, "<span class='blue'>$&</span>");

$('#results').html(newText);
}
.blue{
  background-color: red;
  font: red;
}
.green{
  background-color: green;
}


.greyHighlight:hover{
  background-color: grey;
  color: white;
  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 <form id="myform">
      <fieldset>
        <textarea name='textEntered' id='textEntered' />This is a cool story.</textarea>
        <button type='submit' class="bttn">Enter</button>
      </fieldset>
    </form>
   
    <div class="results-container"> <span class="results-title">Highlighted Text:</span> <div id="results"> </div> <br> </div>


<div class="wantedResults">
Results I wish to have <br>
<span class="blue">This is a</span><span class="green">cool story</span> 
</div>

3 ответа

Решение

Это работает для базовой реализации. Перекрытие более 2 раз не будет работать должным образом. А также необходимо обрабатывать пробелы.

var arr = [
  {str:"cool story",
   color: "green"},
   {str:"This is a cool",
   color: "blue"},
   {str:"two best friends",
   color: "red"},
   {str:"about two best",
   color: "yellow"},
];

$("#myform").submit(function(event){
   event.preventDefault();
   $('#results').html('');
   let text = $('textarea#textEntered').val();
   highlightText(text); 
});

function highlightText(text)
{
    for(var index=0;index<arr.length;index++)
    {
        var matches=text.match(arr[index].str.split(" ").join("\\s*(<.*>)*\\s*"));
        if(matches)
        {
            for(var i=1;i<matches.length;i++)
            {
                if(!matches[i]) continue;
                if(matches[i].indexOf("/")==-1)
                {
                    text = text.replace(matches[0],matches[0].replace(matches[i],"")+matches[i]);
                }
                else
                {
                
                    text = text.replace(matches[0],matches[i]+matches[0].replace(matches[i],""));
                }
            }
        }
        text = text.replace(arr[index].str, "<span class='"+arr[index].color+"'>$&</span>");
    }
    $('#results').append($(text))
}
.blue{
  background-color: blue;
}
.green{
  background-color: green;
}
.red{
  background-color: red;
}
.yellow{
  background-color: yellow;
}
.grey{
  background-color: grey;
}

.greyHighlight:hover{
  background-color: grey;
  color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <form id="myform">
      <fieldset>
        <textarea name='textEntered' id='textEntered'>This is a cool story about two best friends.</textarea>
        <button type='submit' class="bttn">Enter</button>
      </fieldset>
  </form>
   
    <div class="results-container"> <span class="results-title">Highlighted Text:</span> <div id="results"> </div> <br> </div>


<div class="wantedResults">
Results I wish to have <br>
<span class="blue">This is a</span><span class="green">cool story</span> 
</div>

Это может иметь какое-то отношение к перекрытию "это круто" и "круто"? Вы можете переписать один поиск с другим, особенно если вы делаете последний... может включать </span> как часть вашего поиска, как в

this is a cool(</span>)?или жеcool(</span>)? story

Я думаю, что это может выполнить то, что вы хотите. Это не идеально, так как не будет работать, если есть несколько слоев <span> или же </span> но это дает правильный результат в вашем примере. Надеюсь, это поможет каким-то образом:)

let greenListArray = ["cool story"];
let blueListArray = ['This is a cool'];

$("#myform").submit(function(event){
   event.preventDefault();
   $('#results').html('');
   let text = $('textarea#textEntered').val();
   highlightText(text); 
});

function highlightText(text){

    // this replaces all spaces with regex that will allow the capturing of html tags '<>'
    // note that I am only doing this for the first element in the array, this would need to loop over the elements if so desired...
    greenListArray[0] = greenListArray[0].replace(new RegExp(' ', 'g'), '( |<.*>| <.*>|<.*> )');
    blueListArray[0] = blueListArray[0].replace(new RegExp(' ', 'g'), '( |<.*>| <.*>|<.*> )');
    
    let regexGreen = new RegExp(greenListArray.join('[,!?.]?|'), "ig");
    let regexBlue = new RegExp(blueListArray.join('[,!?.]?|'), "ig");
    
    
    text = replaceStuffs(text, regexGreen, 'green');
    text = replaceStuffs(text, regexBlue, 'blue');
    $('#results').html(text);
}

function replaceStuffs(text, regex, classToAdd) {
 let matchRegex = regex.exec(text);
 let needToAppend = true;
 
 matchRegex = matchRegex[0]; // grab the matching string... as it seems to always be the first element in the array returned by .exec...
 
 let replacement = matchRegex;
 
 if (matchRegex.indexOf('<span') !== -1 && matchRegex.indexOf('</span>') !== -1) // there is a beginning and ending span tag... we leave it alone
 {
 }
 else if (matchRegex.indexOf('<span') !== -1 && matchRegex.indexOf('</span>') === -1) // there's a beginning tag. we need to find the ending of that tag, and then append our ending </span>
 {
  let regexTemp = new RegExp('<span.*', "ig"); // lets select as much of this beginning tag as we can, so it'll hopefully be unique.
  let str = regexTemp.exec(matchRegex);
  // debugger; <-- this pauses Chrome's execution of JS. useful for testing...
  str = str[0];
  
  regexTemp = new RegExp(str+'.*</span>', "ig"); // use the string we found, look for the closing </span>
  text = text.replace(regexTemp, '$&</span>'); // we have now put our closing span after the closing </span> that we found.
  needToAppend = false; // set a variable so we don't append the </span> again later...
 }
 else if (matchRegex.indexOf('</span>') !== -1) // closing span, no beginning tag... we need to move it...
 {
  replacement = matchRegex.replace('</span>','');
  replacement += '</span>';
 }
 
 replacement = '<span class="'+classToAdd+'">'+replacement+(needToAppend ? '</span>' : '');
 
 text = text.replace(matchRegex, replacement);
 return text;
}
.blue{
  background-color: red;
  font: red;
}
.green{
  background-color: green;
}


.greyHighlight:hover{
  background-color: grey;
  color: white;
  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 <form id="myform">
      <fieldset>
        <textarea name='textEntered' id='textEntered' />This is a cool story.</textarea>
        <button type='submit' class="bttn">Enter</button>
      </fieldset>
    </form>
   
    <div class="results-container"> <span class="results-title">Highlighted Text:</span> <div id="results"> </div> <br> </div>


<div class="wantedResults">
Results I wish to have <br>
<span class="blue">This is a</span><span class="green">cool story</span> 
</div>

Другие вопросы по тегам