正则表达式选择相邻的模式匹配项作为单个项

时间:2019-01-06 13:51:08

标签: javascript jquery html regex

我正在尝试编写一个脚本,以突出显示网页上与输入内容匹配到搜索框的所有内容,同时忽略搜索匹配项的大小写。

我的html页面看起来像-

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Index Page</title>
    <!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">-->
    <!-- Bootstrap core CSS -->
    <link href="Content/bootstrap.min.css" rel="stylesheet">
    <!-- Your custom styles (optional) -->
    <link href="Content/style.css" rel="stylesheet">
    <!-- custom javascript -->
    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.quicksearch/2.3.1/jquery.quicksearch.js"></script>
    <script src="Scripts/script.js"></script>
</head>
<body>

    <!--Main Navigation-->
    <header>
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <form class="form-inline my-2 my-lg-0">
                    <input class="form-control mr-sm-2" id="txt_query" type="search" placeholder="Search" aria-label="Search">
                    <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
                </form>
        </nav>
    </header>
    <!--Main Navigation-->
    <div class="container-fluid">
        <div class="searchable">
            Hello
            <div>
                test1
            </div>
            <div>
                test2
            </div>
            <div>
                Test3
                <div>
                    teest4
                </div>
            </div>
        </div>
    </div>
</body>
</html>

并且javascript(JQuery)代码是-

$(function () {
    $('input#txt_query').on('input', function () {
        if (this.value !== null) {
            var search_value = this.value;
            var search_regexp;
            if (this.value !== "") {
                search_regexp = new RegExp(search_value + "+(?![^<]*\>)", "gi");
            }
            $('.searchable').each(function () {
                $(this).find('*').each(function () {
                    if ($(this).data('old-state') == null) {
                        $(this).data('old-state', $(this).html());
                    }
                    if (this.value !== "") {
                        var html = $(this).data('old-state').replace(search_regexp, "<span class = 'highlight'>" + search_value + "</span>");
                        //alert(html);
                        $(this).html(html);
                    }
                });
            });
        }
    });
});

突出显示该词的CSS是-

.highlight {
    font-weight: bold;
    color: green;
}

目前有两个问题。

  1. 在匹配术语相邻的地方,这些项目被视为单个项目。因此,当搜索“ e”时,“ ee”将替换为突出显示的“ e”。

  2. 搜索“ t”会找到大写字母“ T”,但将其替换为突出显示的“ t”(小t)。

我认为这两个问题都可以通过修改以下代码行来解决:

var html = $(this).data('old-state').replace(
              search_regexp, 
              "<span class = 'highlight'>" + search_value + "</span>"
);

我想使用regex模式找到的文本而不是'search_value',但我不知道如何访问该文本。

2 个答案:

答案 0 :(得分:1)

尝试replace callback function捕获匹配项并替换为todense并使其e保持原大小写或ee

t

演示:

T
var html = $(this).data('old-state').replace(search_regexp,
  function(match, contents, offset) {
    return "<span class = 'highlight'>" + match + "</span>";
  });
$(function() {
  $('input#txt_query').on('input', function() {
    if (this.value !== null) {
      var search_value = this.value;
      var search_regexp;
      if (this.value !== "") {
        search_regexp = new RegExp(search_value + "+(?![^<]*\>)", "gi");
      }
      $('.searchable').each(function() {
        $(this).find('*').each(function() {
          if ($(this).data('old-state') == null) {
            $(this).data('old-state', $(this).html());
          }
          if (this.value !== "") {
            var html = $(this).data('old-state').replace(search_regexp, function(match, contents, offset) {
              return "<span class = 'highlight'>" + match + "</span>";
            });
            //alert(html);
            $(this).html(html);
          }
        });
      });
    }
  });
});

答案 1 :(得分:0)

Meta Sequence Word Boundary \b

在单词的两端插入一个\b,您将只匹配它们之间的内容。 \b的另一面必须是非单词,例如空格。

Dynamic Regex

要在Regex模式中使用变量,请使用RegExp constructor not the Regex literal

  

?var keyword = new RegExp(variable, 'gi');

不是

  

?var keyword = /variable/gi;

如果您确实使用了变量,则需要先对其进行转义。请注意,\b被转义了:\\b

  

var escaped = `(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${keyword})\\b`;

我注意到问题中缺少template literals,因此如果您不熟悉它们,则值得了解它们,因为它们是具有更好语法的字符串。


演示

此演示将通过将它们包装在<mark>标签中来突出显示匹配的内容。

document.getElementById('search').addEventListener('change', function(e) {
  highlight(this.value, '#content');
});

function highlight(keyword, selector) {
  var node = document.querySelector(selector);
  var html = node.innerHTML;
  var clean = html.replace(/(<mark>|<\/mark>)/, '');
  var escaped = `(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${keyword})\\b`;
  var regex = new RegExp(escaped, `gi`);
  var hits = clean.replace(regex, `<mark>$1</mark>`);
  node.innerHTML = hits;
}
<input id='search' type='search'><input type='button' value='search'>

<article id='content'>
  <ol>
    <li>aircrew</li>
    <li><u>air</u> crew</li>
    <li>playground</li>
    <li><u>play</u> ground</li>
    <li>underground</li>
    <li><u>under</u> ground</li>
    <li>hacksaw</li>
    <li><u>hack</u> saw</li>
    <li>toothpaste</li>
    <li><u>tooth</u> paste</li>
  </ol>

</article>