【问题标题】:Overlapping regex matches with replace method使用替换方法重叠正则表达式匹配
【发布时间】:2018-12-13 11:04:19
【问题描述】:

这里是正则表达式新手!假设我有两个文本数组,我正在搜索一个文本,上面写着。

let text = This is a cool story.
我在文本中寻找这些短语。

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

我想用相应的颜色突出显示数组中的单词。因此,ArrBlue 中的所有单词都会导致文本为蓝色,ArrGreen 为绿色。我像这样创建了两个新的正则表达式..

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>

这是我的快速 sn-p,以更好地了解我的情况。

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>

【问题讨论】:

  • 看起来它已经正常工作了!
  • 不,如果您在表单上按回车键,“突出显示的文本”下方是实际结果,与我在下面的结果不同。 “我希望得到的结果”下面的文本是硬编码的。
  • 是的。但我通过提供Hello cool story 进行了检查,得到了结果,发现 HTML 结构符合预期。
  • 但这不是我想要解决的问题。问题是当两个数组中的单词重叠时,只有顶部的单词会被 span 标签而不是两者替换。

标签: javascript regex overlapping-matches


【解决方案1】:

我认为这可能会实现您想要的。但它并不理想,因为如果有多层 &lt;span&gt;&lt;/span&gt; 它将不起作用,但它确实会在您的示例中产生正确的结果。希望这会在某种程度上有所帮助:)

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>

【讨论】:

    【解决方案2】:

    这可能与“这是一个很酷”和“很酷的故事”重叠有关吗? 你可能会用另一个搜索来写一个搜索,特别是因为你做了后者...... 可能包括 &lt;/span&gt; 作为搜索的一部分,如

    this is a cool(&lt;/span&gt;)? 要么 cool(&lt;/span&gt;)? story

    【讨论】:

      【解决方案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>

      【讨论】:

      • 感谢您的回答!这绝对解决了我的问题!但我很好奇你是否知道如何解决如果我有重复短语的问题,让我们多次说“酷故事酷故事”,它只会突出显示在文本中出现的第一次迭代,而不是全部。
      猜你喜欢
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 2012-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多