Невозможно выделить слово специальным символом в jQuery

У меня есть HTML-страница, как показано ниже. Я хочу выделить слово со специальным знаком внутри. Например, я ищу C#, но C# не выделяется, а другие слова без специального символа выделяются. В чем может быть проблема? Я включил jquery, используемый для выделения.

index.html

<!doctype html>
<html>
<head>
<meta charset = "utf-8">
<meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1">
<meta name = "viewport" content = "width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Example</title>
<style>
  body { min-height: 100vh;background-image: linear-gradient(to right, #74ebd5 0%, #9face6 100%); }
  .container { margin: 150px auto; max-width: 640px; font-family: 'Raleway'; line-height: 1.8;}
    .highlight {background: #FFCD69;color:#222; padding: 5px 10px; border-radius: 3px;}
  </style>
</head>
<body>
  <div class = "container">
  <h1>C C++ C# Java</h1>
  <h1>Java is a programming language</h1>
  </div>
  <div class = "container">
  <p>
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's 
  standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make 
  a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, 
  remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, 
  and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
  <h1>Java is a programming language</h1>
  </div>
   <script src = "https://code.jquery.com/jquery-1.12.4.min.js"></script>
  <script type = "text/javascript" src = "jquery.highlight.js"></script>
  <script>

         $('.container').each(function () {
            $(this).highlight("c#",
            {
                wordsOnly: true, wordsBoundary: '\\b\\W*'
            });
        });
  </script>
</body>
</html>

jquery.highlight.js


/*
 * jQuery Highlight plugin
 *
 * Based on highlight v3 by Johann Burkard
 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
 *
 * Code a little bit refactored and cleaned (in my humble opinion).
 * Most important changes:
 *  - has an option to highlight only entire words (wordsOnly - false by default),
 *  - has an option to be case sensitive (caseSensitive - false by default)
 *  - highlight element tag and class names can be specified in options
 *
 * Usage:
 *   // wrap every occurrence of text 'lorem' in content
 *   // with <span class='highlight'> (default options)
 *   $('#content').highlight('lorem');
 *
 *   // search for and highlight more terms at once
 *   // so you can save some time on traversing DOM
 *   $('#content').highlight(['lorem', 'ipsum']);
 *   $('#content').highlight('lorem ipsum');
 *
 *   // search only for entire word 'lorem'
 *   $('#content').highlight('lorem', { wordsOnly: true });
 *
 *   // search only for the entire word 'C#'
 *   // and make sure that the word boundary can also
 *   // be a 'non-word' character, as well as a regex latin1 only boundary:
 *   $('#content').highlight('C#', { wordsOnly: true , wordsBoundary: '[\\b\\W]' });
 *
 *   // don't ignore case during search of term 'lorem'
 *   $('#content').highlight('lorem', { caseSensitive: true });
 *
 *   // wrap every occurrence of term 'ipsum' in content
 *   // with <em class='important'>
 *   $('#content').highlight('ipsum', { element: 'em', className: 'important' });
 *
 *   // remove default highlight
 *   $('#content').unhighlight();
 *
 *   // remove custom highlight
 *   $('#content').unhighlight({ element: 'em', className: 'important' });
 *
 *
 * Copyright (c) 2009 Bartek Szopka
 *
 * Licensed under MIT license.
 *
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function (jQuery) {
    jQuery.extend({
        highlight: function (node, re, nodeName, className, callback) {
            if (node.nodeType === 3) {
                var match = node.data.match(re);
                if (match) {
                    // The new highlight Element Node
                    var highlight = document.createElement(nodeName || 'span');
                    highlight.className = className || 'highlight';
                    // Note that we use the captured value to find the real index
                    // of the match. This is because we do not want to include the matching word boundaries
                    var capturePos = node.data.indexOf( match[1] , match.index );

                    // Split the node and replace the matching wordnode
                    // with the highlighted node
                    var wordNode = node.splitText(capturePos);
                    wordNode.splitText(match[1].length);

                    var wordClone = wordNode.cloneNode(true);
                    highlight.appendChild(wordClone);
                    wordNode.parentNode.replaceChild(highlight, wordNode);
                    if (typeof callback == 'function') {
                        callback(highlight)   
                    }
                    return 1; //skip added node in parent
                }
            } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                    !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                    !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
                for (var i = 0; i < node.childNodes.length; i++) {
                    i += jQuery.highlight(node.childNodes[i], re, nodeName, className, callback);
                }
            }
            return 0;
        }
    });

    jQuery.fn.unhighlight = function (options) {
        var settings = {
          className: 'highlight',
          element: 'span'
        };

        jQuery.extend(settings, options);

        return this.find(settings.element + '.' + settings.className).each(function () {
            var parent = this.parentNode;
            parent.replaceChild(this.firstChild, this);
            parent.normalize();
        }).end();
    };

    jQuery.fn.highlight = function (words, options, callback) {
        var settings = {
          className: 'highlight',
          element: 'span',
          caseSensitive: false,
          wordsOnly: false,
          wordsBoundary: '\\b'
        };

        jQuery.extend(settings, options);

        if (typeof words === 'string') {
          words = [words];
        }
        words = jQuery.grep(words, function(word, i){
          return word != '';
        });
        words = jQuery.map(words, function(word, i) {
          return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
        });

        if (words.length === 0) {
          return this;
        };

        var flag = settings.caseSensitive ? '' : 'i';
        // The capture parenthesis will make sure we can match
        // only the matching word
        var pattern = '(' + words.join('|') + ')';
        if (settings.wordsOnly) {
            pattern =
                (settings.wordsBoundaryStart || settings.wordsBoundary) +
                pattern +
                (settings.wordsBoundaryEnd || settings.wordsBoundary);
        }
        var re = new RegExp(pattern, flag);

        return this.each(function () {
            jQuery.highlight(this, re, settings.element, settings.className, callback);
        });
    };
}));

Я не смотрел внимательно на код, который вы опубликовали, но эта часть выделяется: wordsOnly: true; учитывая, что # - это, и большинство - если не все - «специальные символы» не считаются буквами, кажется, что поиск только слов является частью проблемы. Вы пробовали wordsOnly: false?

David says reinstate Monica 15.09.2018 11:40

@ Дэвид Томас: Да, пробовал wordsOnly: false. Проблема в том, что он также выделяет отдельные символы. если я ищу c, он также выделяет символ c, который находится между словами. Например, он выделяет c в связи, c в процессе и т. д. Я не хочу, чтобы это было так

Vinod 15.09.2018 11:44

Вы пробовали экранировать # с помощью обратной косой черты?

NielsNet 15.09.2018 12:10

@NielsNet Да, все еще не работает

Vinod 15.09.2018 12:21

@Vinod Я пробовал wordsBoundary: '[\\ b \\ W]' работает.

samabcde 15.09.2018 15:01

@samabcde '[\\ b \\ W]' в этом случае обязательно требует специального символа. В моем коде, например, после изменения на это, если я ищу C. Он не выделяет символ c в <h1>C C++ C# Java</h1>

Vinod 17.09.2018 08:12
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
6
512
1

Ответы 1

Приведенный ниже фрагмент кода демонстрирует эффект при настройке различных wordBoundary.

(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function(jQuery) {
  jQuery.extend({
    highlight: function(node, re, nodeName, className, callback) {
      if (node.nodeType === 3) {
        var match = node.data.match(re);
        if (match) {
          // The new highlight Element Node
          var highlight = document.createElement(nodeName || 'span');
          highlight.className = className || 'highlight';
          // Note that we use the captured value to find the real index
          // of the match. This is because we do not want to include the matching word boundaries
          var capturePos = node.data.indexOf(match[1], match.index);

          // Split the node and replace the matching wordnode
          // with the highlighted node
          var wordNode = node.splitText(capturePos);
          wordNode.splitText(match[1].length);

          var wordClone = wordNode.cloneNode(true);
          highlight.appendChild(wordClone);
          wordNode.parentNode.replaceChild(highlight, wordNode);
          if (typeof callback == 'function') {
            callback(highlight)
          }
          return 1; //skip added node in parent
        }
      } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
        !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
        !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
        for (var i = 0; i < node.childNodes.length; i++) {
          i += jQuery.highlight(node.childNodes[i], re, nodeName, className, callback);
        }
      }
      return 0;
    }
  });

  jQuery.fn.unhighlight = function(options) {
    var settings = {
      className: 'highlight',
      element: 'span'
    };

    jQuery.extend(settings, options);

    return this.find(settings.element + '.' + settings.className).each(function() {
      var parent = this.parentNode;
      parent.replaceChild(this.firstChild, this);
      parent.normalize();
    }).end();
  };

  jQuery.fn.highlight = function(words, options, callback) {
    var settings = {
      className: 'highlight',
      element: 'span',
      caseSensitive: false,
      wordsOnly: false,
      wordsBoundary: '\\b'
    };

    jQuery.extend(settings, options);

    if (typeof words === 'string') {
      words = [words];
    }
    words = jQuery.grep(words, function(word, i) {
      return word != '';
    });
    words = jQuery.map(words, function(word, i) {
      return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
    });

    if (words.length === 0) {
      return this;
    };

    var flag = settings.caseSensitive ? '' : 'i';
    // The capture parenthesis will make sure we can match
    // only the matching word
    var pattern = '(' + words.join('|') + ')';
    //console.info(pattern);
    if (settings.wordsOnly) {
      pattern =
        (settings.wordsBoundaryStart || settings.wordsBoundary) +
        pattern +
        (settings.wordsBoundaryEnd || settings.wordsBoundary);
    }
    //console.info(pattern);
    var re = new RegExp(pattern, flag);

    return this.each(function() {
      jQuery.highlight(this, re, settings.element, settings.className, callback);
    });
  };
}));
<!doctype html>
<html>

<head>
  <meta charset = "utf-8">
  <meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1">
  <meta name = "viewport" content = "width=device-width, initial-scale=1, shrink-to-fit=no">
  <script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src = "https://github.com/knownasilya/jquery-highlight/blob/master/jquery.highlight.js"></script>
  <title>Example</title>
  <style>
    body {
      min-height: 100vh;
      background-image: linear-gradient(to right, #74ebd5 0%, #9face6 100%);
    }
    
    .container .container2 .container3 {
      margin: 10px auto;
      max-width: 640px;
      font-family: 'Raleway';
      line-height: 1.8;
    }
    
    .highlight {
      background: pink;
      color: #222;
      padding: 5px 10px;
      border-radius: 3px;
    }
    
    .highlight2 {
      background: #EE0000;
      color: #222;
      padding: 5px 10px;
      border-radius: 3px;
    }
    
    .highlight3 {
      background: #00EE00;
      color: #222;
      padding: 5px 10px;
      border-radius: 3px;
    }
  </style>
</head>

<body>
  <p>Using <b>\\b\\W*</b></p>
  <div class = "container">
    <p>++F a C++ Java a ++D a E++</p>
    <p>Z a language</p>
    <p>++G++</p>
  </div>
  <p>Using <b>\\W*\\b</b></p>
  <div class = "container2">
    <p>++F a C++ Java a ++D a E++</p>
    <p>Z a language</p>
    <p>++G++</p>
  </div>
  <p>Using Start:<b>(?:^|\\W*\\b|\\b\\W*)</b> End:<b>(?:$|\\W*\\b|\\b\\W*)</b></p>
  <div class = "container3">
    <p>++F a C++ Java a ++D a E++</p>
    <p>Z a language</p>
    <p>++G++</p>
  </div>
  <script>
    $(function() {
      var searchList = ["Z",  "java","c++", "++D", "E++", "++F", "language","++G++"];
      $('.container').each(function() {
        $(this).highlight(searchList, {
          wordsOnly: true,
          wordsBoundary: '\\b\\W*'
        });
      });
      $('.container2').each(function() {
        $(this).highlight(searchList, {
          wordsOnly: true,
          className: 'highlight2',
          wordsBoundary: '\\W*\\b'
        });
      });
      $('.container3').each(function() {
        $(this).highlight(searchList, {
          wordsOnly: true,
          className: 'highlight3',
          wordsBoundaryStart: '(?:^|\\W*\\b|\\b\\W*)',
          wordsBoundaryEnd: '(?:$|\\W*\\b|\\b\\W*)'
        });
      });
    });
  </script>
</body>

</html>

Как цитата из Документация по API из jquery-highlight

wordsBoundary -- If wordsOnly is set to true, this is used to determine these boundaries, defaults to \b (word boundary).
wordsBoundaryStart -- If wordsOnly is set to true, this is used to determine prefix word boundaries, defaults to the value of wordsBoundary.
wordsBoundaryEnd -- If wordsOnly is set to true, this is used to determine suffix word boundaries, defaults to the value of wordsBoundary.

Для wordsBoundary \b\W* поисковое выражение станет \b\W*(target word)\b\W*, это означает
. 1. начните с позиции границы слова между словом и не символом слова (\ b),
2. за которым следует ноль или более несловых символов (\ W *),
3. затем целевое слово
4. затем позиция границы слова между словом и не символом слова (\ b),
5. заканчиваться нулевым или более несловым символом (\ W *).

Следовательно, можно искать слово ++DНачните с несловесным символом. И для противоположного случая \W*\b(target word)\W*\b, можно искать слово C++конец с символом, отличным от слова. Обратите внимание, что ++F и E++ не совпадают, надеюсь, что кто-то, знакомый с Regex, может помочь объяснить.

В любом случае, это подсказка, что объединение первого и второго выражения должно быть тем, что мы ищем. Поскольку нам нужны разные выражения в начале и в конце, мы можем использовать опции wordsBoundaryStart и wordsBoundaryEnd. Затем, используя оператор или |, чтобы объединить первое и второе выражение и добавить начало (^) в wordsBoundaryStart, конец ($) в wordsBoundaryEnd, целевые слова будут выделены. Поскольку метод highlight будет рассматривать первую группу как цель выделения, нам нужно использовать не захватывающую группу (?:) для условия «или».

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