Regex выбирает соседние элементы сопоставления с образцом как один элемент - PullRequest
0 голосов
/ 06 января 2019

Я пытаюсь написать скрипт, который выделяет на веб-странице все, что соответствует вводу в поле поиска, игнорируя регистр при поиске совпадений.

Моя 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;
}

В настоящее время есть 2 проблемы.

  1. Там, где совпадающие термины являются смежными, элементы рассматриваются как один элемент. Таким образом, при поиске «e» «ee» заменяется подсвеченным «e».

  2. Поиск 't' находит заглавную 'T', но заменяет ее выделенным 't' (маленькая t).

Я думаю, что обе проблемы могут быть решены путем изменения следующей строки кода:

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

Вместо 'search_value' я хотел бы использовать текст, найденный шаблоном регулярных выражений, но я не знаю, как получить к нему доступ.

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Попробуйте заменить функцию обратного вызова для захвата совпадений и замените ее так, чтобы 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);
          }
        });
      });
    }
  });
});
.highlight {font-weight: bold;color: green;}
.searchable {font-size: 24px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="txt_query" type="search">
<div class="container-fluid">
  <div class="searchable">
    Hello
    <div>
      test1
    </div>
    <div>
      test2
    </div>
    <div>
      Test3
      <div>
        teest4
      </div>
    </div>
  </div>
</div>
0 голосов
/ 06 января 2019

Граница слова метапоследовательности \b

Поставьте \b на обоих концах своего слова, и вы будете сопоставлять только то, что находится между ними. Другая сторона \b должна быть не словом как пробел.

Динамическое регулярное выражение

Чтобы использовать переменную в шаблоне Regex, используйте конструктор RegExp, а не литерал Regex .

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

не

? var keyword = /variable/gi;

Если вы используете переменную, вам сначала нужно ее экранировать. Обратите внимание, что \b s экранированы: \\b

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

Я заметил отсутствие литералов шаблонов в вопросе, поэтому, если вы не знакомы с ними, стоит их узнать, это строки с лучшим синтаксисом.


Демо

Эта демонстрация будет подсвечивать то, что соответствует, оборачивая их в теги <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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...