Wrap search phrases that may start or end with special characters and have common prefixes as whole words only with SPAN tag

本秂侑毒 提交于 2021-02-05 09:27:44

问题


I have this code to highlight words that exist in an array everything works fine except it didn't highlight the words that contain '.'

spansR[i].innerHTML = t[i].replace(new RegExp(wordsArray.join("|"),'gi'), function(c) {
                return '<span style="color:red">'+c+'</span>';
            });

I also tried to escape dot in each word

 for(var r=0;r<wordsArray.length;r++){
               if(wordsArray[r].includes('.')){
                 wordsArray[r] = wordsArray[r].replace(".", "\\.");
                  wordsArray[r] = '\\b'+wordsArray[r]+'\\b';
              }
           }

I also tried to change replace by those and non of them worked "replace(".", "\.")" , "replace(".", "\.")" , "replace(".", "/.")" , "replace('.','/.')" , "replace('.','/.')" .

This is a simplified test case (I want to match 'free.' )

    <!DOCTYPE html>
<html>
<body>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
  var re = "\\bfree\\.\\b";
  var str = "The best things in life are free.";
  var patt = new RegExp(re);
  var res = patt.test(str);
  document.getElementById("demo").innerHTML = res;
}
</script>
</body>
</html>

回答1:


Implement an unambiguous word boundary in JavaScript.

Here is a version for JS that does not support ECMAScript 2018 and newer:

var t = "Some text... firas and firas. but not firass ... Also, some shop and not shopping";
var wordsArray = ['firas', 'firas.', 'shop'];
wordsArray.sort(function(a, b){
  return b.length - a.length;
});
var regex = new RegExp("(^|\\W)(" + wordsArray.map(function(x) {
  return x.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
}).join("|") + ")(?!\\w)",'gi');
console.log( t.replace(regex, '$1<span style="color:red">$2</span>') );

Here, the regex will look like /(^|\W)(firas\.|firas|shop)(?!\w)/gi, see demo. The (^|\W) captures into Group 1 ($1) start of string or a non-word char, then there is a second capturing group that catures the term in question and (?!\w) negative lookahead matches a position that is not immediately followed with a word char.

The wordsArray.sort is important, as without it, the shorter words with the same beginning might "win" before the longer ones appear.

The .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') is a must to escape special chars in the search terms.

A variation for JS environments that support lookbehinds:

let t = "Some text... firas and firas. but not firass ... Also, some shop and not shopping";
let wordsArray = ['firas', 'firas.', 'shop'];
wordsArray.sort((a, b) => b.length - a.length );
let regex = new RegExp(String.raw`(?<!\w)(?:${wordsArray.map(x => x.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join("|")})(?!\w)`,'gi');
console.log( t.replace(regex, '<span style="color:red">$&</span>') );

The regex will look like /(?<!\w)(?:firas\.|firas|shop)(?!\w)/gi, see demo. Here, (?<!\w) negative lookbehind matches a location that is not immediately preceded with a word char. This also makes capturing group redundant and I replaced it with a non-capturing one, (?:...), and the replacement pattern now contains just one placeholder, $&, that inserts the whole match.




回答2:


Here is your solution:

Replace this:

new RegExp(wordsArray.join("|"),'gi')

With this:

new RegExp(wordsArray.join("|"),'gi').replace(/\./g,'\\.')

Example :

['javascript', 'firas.', 'regexp'].join("|").replace(/\./g,'\\.')

Will print

javascript|firas\.|regexp

Which is the regular expression you are looking for, with the escaped dot. It will match firas. but it will not match firas, as you specifically asked in your last comment



来源:https://stackoverflow.com/questions/58952500/wrap-search-phrases-that-may-start-or-end-with-special-characters-and-have-commo

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!