Jquery как найти ссылку по тексту

All answers so far do not match all specific elements containing a direct child text node which contains a specific text.

Consider the following example. We want to find all hobbits, that is, all divs containing a direct child text node, which contains the word «hobbit» (including word borders, ignoring the case).

$(function() {
    
    const ELEMTYPE = Node.ELEMENT_NODE
    const TEXTTYPE = Node.TEXT_NODE
    
    /*
    Behaves a bit like Python's os.walk().
    The `topdown` parameter is not strictly necessary for this example.
    */
    function* walk_text(root, topdown=true) {
        const childs = []
        const textchilds = []
        for (const child of root.childNodes) {
            const childtype = child.nodeType
            if (childtype === ELEMTYPE) {
                childs.push(child)
            } else if (childtype === TEXTTYPE) {
                textchilds.push(child)
            }
        }
        if (topdown) {
            yield [root, textchilds]
        }
        for (const child of childs) {
            yield* walk_text(child, topdown)
        }
        if (!topdown) {
            yield [root, textchilds]
        }
    }
    
    function* walk_matching(startnode, nodepat, textpat) {
        for ( [elem, textchilds] of walk_text(startnode) ) {
            if ( nodepat.test(elem.nodeName) ) {
                for ( const textchild of textchilds ) {
                    if ( textpat.test(textchild.nodeValue) ) {
                        yield elem
                        break
                    }
                }
            }
        }
    }
    
    // raw dom node
    let startnode = $('body')[0]
    
    // search for element nodes with names matching this pattern ...
    let nodepat = /^div$/i
    
    // ... containing direct child text nodes matching this pattern
    let textpat = /bhobbitb/i
    
    for ( const node of walk_matching( startnode, nodepat, textpat ) ) {
        $(node).css({
            border: '1px solid black',
            color: 'black'
        })
    }

});
div {
    margin:10px 0;
    padding: 10px;
    border: 1px solid silver;
    color: silver;
    font-style:italic;
}

div:before {
    display:block;
    content: attr(name);
    font-style:normal;
}

/* Inserted by SO, we are not interested in it */
body + div {
    display: none;
}
<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Find the hobbits</title>
    </head>
    <body>
        <div name='Tolkien'>
            book writer
            <div name='Elrond'>
                elven king
                <div name='Arwen'>elven princess</div>
                <div name='Aragorn'>human king, son-in-law</div>
            </div>
            <div name='Gandalf'>
                wizard, expert for hobbits
                <div name='Bilbo'>
                    old hobbit
                    <div name='Frodo'>
                        young hobbit
                        <div name='Samweis'>best friend hobbit</div>
                    </div>
                </div>
                <div name='Gollum'>ex hobbit</div>
                <div name='Odo'>hobbit</div>
            </div>
        </div>
        <script src= "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    </body>
</html>

The other answers find (when searching for ‘hobbit’):

  • Rocket Hazmat’s answer: Tolkien, Gandalf, Bilbo, Frodo, Samweis, Gollum, Odo
  • Morgs’s answer: Tolkien
  • yoav barnea’s answer: Gandalf, Frodo
  • Nicholas Sushkin’s answer: Samweis, Gollum, Odo
  • Rocket Hazmat’s answer in the comments, Terry Lin’s answer, rplaurindo’s answer: Odo

All of these answers make sense, depending on what you want to do. Choose wise, because Rocket Hazmat’s answers, Morgs’s answer and Terry Lin’s answer partially perform more than two times faster than my solution. I guess that is because they don’t need to walk through the whole DOM. Most answers who use .filter() perform very fast.

I suspect that I could much improve upon this, though at the minute this is the best I can offer (albeit I think that some kind of replace might work more efficiently):

var $words = $('p').text().split(' ');
for (i in $words) {
    if ($words[i].indexOf('http://') == 0) {
        $words[i] = '<a href="' + $words[i] + '">' + $words[i] + '</a>';
    }
}

$('p').html($words.join(' '));

JS Fiddle demo.

A slightly improved version of the above (but good lord, it’s ugly…):

var punctuation = ['!',"'",'"',',','.'];
$('p').each(
    function(){
        $words = $(this).text().split(' ');
        for (i in $words){
            if ($.inArray($words[i].charAt(0),punctuation) > -1 && $words[i].indexOf('http://') == 1){
                alert($words[i]);
            }
            else if ($.inArray($words[i].charAt($words[i].length - 1),punctuation) > -1 && ($words[i].indexOf('http://') == 1 || $words[i].indexOf('http://') == 0)){
                $words[i] = '<a href="'+$words[i].substring(0,$words[i].length-1)+'">' + $words[i].substring(0,$words[i].length-1) + '</a>' + $words[i].charAt($words[i].length-1);
            }
            else if ($words[i].indexOf('http://') == 0){
                $words[i] = '<a href="' + $words[i] + '">' + $words[i] + '</a>';
            }
        }
        $(this).html($words.join(' '));
    });

JS Fiddle demo.

I’m not quite sure what to do about quoted links, though (text such as "http://google.com", for example); and, honestly, I think that regex is probably the far, far better approach to this problem.

Время на прочтение
5 мин

Количество просмотров 47K

Многие посетители сайтов не знают о поиске по странице по нажатию Ctrl+F и ищут необходимый фрагмент глазами, просто пролистывая текст. Этот способ становится проблематичным, если на странице текста больше, чем три-четыре экрана. Для таких посетителей я решил реализовать поиск по странице с использованием jQuery.
Пример подобного поиска есть на сайте Конституции РФ, но там он работает как-то странно.

Предупреждение

Я не профессиональный программист, просьба не пинать за кривой код и возможное изобретение велосипеда.

HTML-форма

Первым делом разместим на странице HTML-код формы поиска. Форма включает два элемента — поле для ввода текста и DIV для вывода результатов поиска.

<input id="spterm" type="text" name="spterm" placeholder="Что искать?"><br />
<div id="spresult"> </div>

CSS

Задаём два стиля: первый — для выделения фрагмента, второй — для ссылки на первый фрагмент.

span.highlight {
background-color: #C6D9DB; cursor: pointer; }
span.splink {
color: #0A5794; cursor: pointer; }

Настройка поиска

 var minlen = 3; // минимальная длина слова
 var paddingtop = 30; // отступ сверху при прокрутке
 var scrollspeed = 200; // время прокрутки
 var keyint = 1000; // интервал между нажатиями клавиш

Подсветка фрагментов

Базовая функциональность — подсветка фрагментов в тексте. Делается это с помощью регулярных выражений.

function dosearch() {
  term = jQuery('#spterm').val();
  jQuery('span.highlight').each(function(){ //удаляем старую подсветку
   jQuery(this).after(jQuery(this).html()).remove();  
  });
  var t = '';
  jQuery('div.entry-content').each(function(){ // в селекторе задаем область поиска
   jQuery(this).html(jQuery(this).html().replace(new RegExp(term, 'ig'), '<span class="highlight">$&</span>')); // выделяем найденные фрагменты
   n = jQuery('span.highlight').length; // количество найденных фрагментов
   console.log('n = '+n);
   if (n==0)
    jQuery('#spresult').html('Ничего не найдено');
   else
    jQuery('#spresult').html('Результатов: '+n); 
  });
 }

jQuery('#spterm').keyup(function(){
  if (jQuery('#spterm').val()!=term) // проверяем, изменилась ли строка
   if (jQuery('#spterm').val().length>=minlen) { // проверяем длину строки
    dosearch(); // если все в порядке, приступаем к поиску
   }
   else
    jQuery('#spresult').html(' '); // если строка короткая, убираем текст из DIVа с результатом 
 });

Переход между фрагментами

Мало просто выделить фрагменты, гораздо удобнее организовать быстрый переход между ними. Под формой размещаем ссылку перехода на первый найденный фрагмент. Чтобы не занимать место стрелками, клик на каждый фрагмент ведет к следующему. Клик на последний фрагмент возвращает пользователя к форме поиска.

   if (n==0)
    jQuery('#spresult').html('Ничего не найдено');
   else
    jQuery('#spresult').html('Результатов: '+n); 
if (n>1) // если больше одного фрагмента, то добавляем переход между ними
   {
    var i = 0;
    jQuery('span.highlight').each(function(i){
     jQuery(this).attr('n', i++); // нумеруем фрагменты, более простого способа искать следующий элемент не нашел
    });
    jQuery('span.highlight').not(':last').attr({title: 'Нажмите, чтобы перейти к следующему фрагменту'}).click(function(){ // всем фрагментам, кроме последнего, добавляем подсказку
     jQuery('body,html').animate({scrollTop: jQuery('span.highlight:gt('+jQuery(this).attr('n')+'):first').offset().top-paddingtop}, scrollspeed); // переход к следующему фрагменту
    });
    jQuery('span.highlight:last').attr({title: 'Нажмите, чтобы вернуться к форме поиска'}).click(function(){
     jQuery('body,html').animate({scrollTop: jQuery('#spterm').offset().top-paddingtop}, scrollspeed); // переход к форме поиска
    });
   }

Задержка запуска поиска

Поиск в большом тексте и подсветка занимают несколько секунд, на которые страница зависает. При наборе длинного слова поиск производится после каждой введённой буквы.

 jQuery('#spterm').keyup(function(){
  var d1 = new Date();
  time_keyup = d1.getTime();
  if (jQuery('#spterm').val()!=term) // проверяем, изменилась ли строка
   if (jQuery('#spterm').val().length>=minlen) { // проверяем длину строки
    setTimeout(function(){ // ждем следующего нажатия
     var d2 = new Date();
     time_search = d2.getTime();
     if (time_search-time_keyup>=keyint) // проверяем интервал между нажатиями
      dosearch(); // если все в порядке, приступаем к поиску
    }, keyint); 
   }
   else
    jQuery('#spresult').html(' '); // если строка короткая, убираем текст из DIVа с результатом 
 });	

Бонус

Добавим возможность создавать ссылки на любой текст на странице без использования <a name=»…»>. Достаточно создать ссылку на страницу и добавить #текст.

 if (window.location.hash!="") // бонус
 {
  var t = window.location.hash.substr(1, 50); // вырезаем текст
  jQuery('#spterm').val(t).keyup(); // вставляем его в форму поиска
  jQuery('#spgo').click(); // переходим к первому фрагменту
 }

Весь код

jQuery(document).ready(function(){
 var minlen = 3; // минимальная длина слова
 var paddingtop = 30; // отступ сверху при прокрутке
 var scrollspeed = 200; // время прокрутки
 var keyint = 1000; // интервал между нажатиями клавиш
 var term = '';
 var n = 0;
 var time_keyup = 0;
 var time_search = 0;
 
 jQuery('body').delegate('#spgo', 'click', function(){
  jQuery('body,html').animate({scrollTop: jQuery('span.highlight:first').offset().top-paddingtop}, scrollspeed); // переход к первому фрагменту
 });
 
 function dosearch() {
  term = jQuery('#spterm').val();
  jQuery('span.highlight').each(function(){ //удаляем старую подсветку
   jQuery(this).after(jQuery(this).html()).remove();  
  });
  var t = '';
  jQuery('div#content').each(function(){ // в селекторе задаем область поиска
   jQuery(this).html(jQuery(this).html().replace(new RegExp(term, 'ig'), '<span class="highlight">$&</span>')); // выделяем найденные фрагменты
   n = jQuery('span.highlight').length; // количество найденных фрагментов
   console.log('n = '+n);
   if (n==0)
    jQuery('#spresult').html('Ничего не найдено');
   else
    jQuery('#spresult').html('Результатов: '+n+'. <span class="splink" id="spgo">Перейти</span>'); 
   if (n>1) // если больше одного фрагмента, то добавляем переход между ними
   {
    var i = 0;
    jQuery('span.highlight').each(function(i){
     jQuery(this).attr('n', i++); // нумеруем фрагменты, более простого способа искать следующий элемент не нашел
    });
    jQuery('span.highlight').not(':last').attr({title: 'Нажмите, чтобы перейти к следующему фрагменту'}).click(function(){ // всем фрагментам, кроме последнего, добавляем подсказку
     jQuery('body,html').animate({scrollTop: jQuery('span.highlight:gt('+jQuery(this).attr('n')+'):first').offset().top-paddingtop}, scrollspeed); // переход к следующему фрагменту
    });
    jQuery('span.highlight:last').attr({title: 'Нажмите, чтобы вернуться к форме поиска'}).click(function(){
     jQuery('body,html').animate({scrollTop: jQuery('#spterm').offset().top-paddingtop}, scrollspeed); // переход к форме поиска
    });
   } 
  });
 }

 jQuery('#spterm').keyup(function(){
  var d1 = new Date();
  time_keyup = d1.getTime();
  if (jQuery('#spterm').val()!=term) // проверяем, изменилась ли строка
   if (jQuery('#spterm').val().length>=minlen) { // проверяем длину строки
    setTimeout(function(){ // ждем следующего нажатия
     var d2 = new Date();
     time_search = d2.getTime();
     if (time_search-time_keyup>=keyint) // проверяем интервал между нажатиями
      dosearch(); // если все в порядке, приступаем к поиску
    }, keyint); 
   }
   else
    jQuery('#spresult').html(' '); // если строка короткая, убираем текст из DIVа с результатом 
 });	
 
 if (window.location.hash!="") // бонус
 {
  var t = window.location.hash.substr(1, 50); // вырезаем текст
  jQuery('#spterm').val(t).keyup(); // вставляем его в форму поиска
  jQuery('#spgo').click(); // переходим к первому фрагменту
 } 
});

Недостатки

На больших страницах (примерно 60 кб текста) скрипт зависает на пару минут.

Демо: http://jsfiddle.net/6c3ph7uj/2/

Спасибо за внимание, буду благодарен за замечания и идеи по улучшению работы скрипта.

Цель

Необходим скрипт который будет заменять URL’ы страницы на HTML ссылки (<a></a>). Если URL уже обрамлен тегом <a>, т.е. уже является ссылкой, то нечего не делать. URL может начинаться с http, https или ftp. URL может содержать как латинские так и кириллические символы.

Решение

Код плагина:

jQuery(function($) {
    var re = /((http|https|ftp)://[a-zа-я0-9w?=&./-;#~%-]+(?![a-zа-я0-9ws?&./;#~%"=-]*>))/g;
    function makeHTML(textNode) {
        var source = textNode.data;
        return source.replace(re, function() {
            var url = arguments[0];
            var a = $('<a></a>').attr({'onclick' : 'window.open('' + url + ''); return false;','href': '#', 'target': '_blank'}).text(url);
            return url.match(/^https?://$/) ? url : $('<div></div>').append(a).html();
        });
    };
    function eachText(node, callback) {
        $.each(node.childNodes, function() {
            if (this.nodeType != 8 && this.nodeName != 'A') {
                this.nodeType != 1 ? callback(this) : eachText(this, callback);
            }
        });
    };
    $.fn.autolink = function() {
        return this.each(function() {
            var queue = [];
            eachText(this, function(e) {
                var html = makeHTML(e);
                if (html != e.data) {
                    queue.push([e, makeHTML(e)]);
                }
            });
            $.each(queue, function(i, x) {
                $(x[0]).replaceWith(x[1]);
            });
        });
    };
});

Сохраняем этот код в js файл, например autolink.js

Как использовать

Пример использования:

<!DOCTYPE html>
<html>
    <head>
        <title>autolink test</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
        <script type="text/javascript" src="autolink.js"></script>
        <script>
            jQuery(function ($) {
                $('.content').autolink();
            });
        </script>
    </head>
    <body>
        <div class="content">
            <p>Test: http://devreadwrite.com/</p>
            <p>Тест: http://кодер.укр/</p>
        </div>
    </body>
</html>

Для автозамены всех URL на странице необходимо поменять код с:

jQuery(function ($) {
    $('.content').autolink();
});

на:

jQuery(function ($) {
    $('document.body').autolink();
});

Скачать

GitHub: https://github.com/egor/jquery-autolink.git

Я подозреваю, что я мог бы улучшить это, хотя в тот момент это лучшее, что я могу предложить (хотя я думаю, что какая-то замена может работать более эффективно):

var $words = $('p').text().split(' ');
for (i in $words) {
    if ($words[i].indexOf('http://') == 0) {
        $words[i] = '<a href="' + $words[i] + '">' + $words[i] + '</a>';
    }
}

$('p').html($words.join(' '));

Демо-версия JS Fiddle.

Немного улучшенная версия выше (но хороший лорд, это уродливо…):

var punctuation = ['!',"'",'"',',','.'];
$('p').each(
    function(){
        $words = $(this).text().split(' ');
        for (i in $words){
            if ($.inArray($words[i].charAt(0),punctuation) > -1 && $words[i].indexOf('http://') == 1){
                alert($words[i]);
            }
            else if ($.inArray($words[i].charAt($words[i].length - 1),punctuation) > -1 && ($words[i].indexOf('http://') == 1 || $words[i].indexOf('http://') == 0)){
                $words[i] = '<a href="'+$words[i].substring(0,$words[i].length-1)+'">' + $words[i].substring(0,$words[i].length-1) + '</a>' + $words[i].charAt($words[i].length-1);
            }
            else if ($words[i].indexOf('http://') == 0){
                $words[i] = '<a href="' + $words[i] + '">' + $words[i] + '</a>';
            }
        }
        $(this).html($words.join(' '));
    });

Демо-версия JS Fiddle.

Я не совсем уверен, что делать с цитируемыми ссылками (например, например, "http://google.com"); и, честно говоря, я думаю, что регулярное выражение, вероятно, далеко, гораздо лучший подход к этой проблеме.

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти несовпадение в таблицах excel
  • Как найти объем производства в натуральном выражении
  • Исправьте ошибки как избежать такую ошибку
  • Как найти родственников участника вов по фамилии
  • Как найти потерянный huawei p40 lite e

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии