Поиск выражения в тексте
Есть текст в котором могут присутсвовать ссылки на YouTube , в таком формате http://www.youtube.com/watch?v=iuOcLoqo5e0 вот пример текста
Код:
Google points to voice search as vital to the company's endeavours in building a presence on the mobile web. Думал отследить эти ссылки таким способом jQuery('a[href~=youtube.com/watch?v=]') Но проблема в том что атрибуда <a> нету у меня , есть просто текст. Заранее благодарен. |
самый простой по логике способ:
получаем сисок всех нод с помощью getElementsByTagName('*') перебираем их в цикле, а внутри цикла перебираем всех их потомков, являющихкся текстовыми нодами каждый из них проверяемя на вхождение подстроки, и делаем с ним необходимое действие меньше десятка строк, и никакого jQuery на нем, же я не знаю как это реализовать, и есть ли для этого эффективные инструменты я вроде бы слышал, что jQuery позволяет искать элементы использую XPath-синтаксис. |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>blank</title> <script type="text/javascript" src="scripts/base.debug.js"></script> <script type="text/javascript"> window.onload = function() { var arr = document.body.innerHTML.match(/http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11}/gi); alert( arr.join('\n') ); }; </script> </head> <body> Google points to voice search as vital to the company's endeavours in building a presence on the mobile web. http://www.youtube.com/watch?v=iuOcLFFo5e1 fgfdgfd fghgfh fdgfdgfd dfsd http://www.youtube.com/watch?v=iuOcLoqo5e0 dsfs dsfds </body> </html> |
Riim,
вы сами пытались запустить этот пример на странице большей, чем ваш тестовый пример? или вы считаете по несколько раз перерисовывать окно это хорошо? |
Если нужно их только найти то это вероятно лучший способ. Я просто забыл, что их еще и в тег "a" запихнуть надо. Невнимательно вопрос читал.
|
Только вот у текстовых узлов innerHTML-а нету. И как поменять часть такого узла? Вероятно, придется брать его родителя и заменять часть через innerHTML. А этот родитель может тоже много чего содержать, и все это будет перерисовываться. Думаю, если другого способа нет, то лучше это на сервере делать. И ссылки будут рабочие до onload.
|
Riim,
во первых, если даже считать, что мы ничего не можем сделать с текстовым узлом, а только с его родителем, это в разы лучше, чем перерисовывать ВЕСЬ документ. вы-вторых, у текстовых нодов есть замечательное свойство nodeValue, которое доступно для редактирования. помимо это есть куча замечательных методов типа inserBefore и прочих. с их помощью много чего можно намутить, и при этом перерисовыватся будет минимум страницы то есть только для проверки самого факта наличия ваш код подходит, и он быстрее. для любой модификации в указанном месте, он уже не подходит |
>>> во первых, если даже считать, что мы ничего не можем сделать с текстовым узлом, а только с его родителем, это в разы лучше, чем перерисовывать ВЕСЬ документ.
Да я ж не спорю. >>> для любой модификации в указанном месте, он уже не подходит Если указанное место это див с текстом и без элементов. Замечательно подойдет |
Цитата:
во вторых, чисто текстовый див не был оговорен в условии топикстартера, и вообще является ситуацией скорее искуственой, чем реальной |
Про весь документ я и не спорю, а про указанное место ты сам начал.
|
Попробовал nodeValue. Он тоже не подходит т. к. экранирует теги как innerText. Вот:
var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0, length = childNodes.length; i < length; i++) { var I = childNodes[i]; I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; window.onload = function() { TextNode.each(function(noda) { noda.nodeValue = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); }); }; Или я что то не так делаю? |
Получилось через replaceChild:
var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0, length = childNodes.length; i < length; i++) { var I = childNodes[i]; I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; window.onload = function() { TextNode.each(function(noda) { var elem = document.createElement('div'); elem.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); noda.parentNode.replaceChild(elem, noda); }); }; |
Цитата:
я не уверен, насчет replaceChild и его кросбраузерности. не проверял. я лично в таком случае использовал insertBefore и removeChild текстовые ноды могут быть не только у body-элемента. они могут быть потомками любого тега, поэтому надо получить всю коллекцию, и для всех тегов перебрать, например |
Riim, а зачем ты div создаешь? Во-первых, ты добавляешь div'ы, которых изначально не было, а во-вторых может поменяться внешний вид
кроме того, я бы не записывал столько всего в for: var childNodes = (parent || document.body).childNodes; length = childNodes.length; for (i = 0; i < length; i++) { и использовал бы if'ы вместо тернарного оператора if( I.nodeType == 1 ) arguments.callee(callback, I); elseif( I.nodeType == 3 ) callback(I, i); а еще, может, регулярное выражение можно проще сделать, но это зависит от наличия других ссылок в тексте |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Что касается читаемости, то, на мой взгляд, при нормальном оформлении тернарного оператора, он читается лучше, чем if-else. |
Цитата:
window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { var n = noda.nextSibling, p = noda.parentNode; do p.insertBefore(div.firstChild, n); while (div.firstChild); p.removeChild(noda); } }); }; Теперь нет никаких лишних тегов. |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
ИМХО, незначительно. более того это можно было бы назвать преждевременной оптимизацией, и потому подход этот вреден. вам тернарный оператор нормально читается, а большинству нет. то есть ваш подход приемлим, только если вы в одиночку пишите жестко инкапсулированый код, которй предполагаете никто кроме вас дорабатывать не должен. |
Цитата:
Цитата:
У меня код уменьшается минимум на 15%. Думаете, я преувеличиваю? Нет, потому что на результат можно по-разному смотреть. Я, например, смотрю на него после работы YUICompressor-а. Считайте сами, каждая локальная переменная, например "parentNode", становиться одной буквой, то есть "parentNode" уменьшиться в 10 раз. В результате объем операторов в коде, в процентах, становиться довольно значительным и экономить на них уже довольно выгодно. Цитата:
С другой, вот, попадется вам какой ни будь плагин к Jquery (а большинство из них пишутся примерно в этом же стиле) и будите с ним мучиться. У меня с этим проблем нет т. к. свободно воспринимаю самые разные стили. Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
мой вариант: window.onload = function() { TextNode.each(function(noda) { var div = document.createElement( 'div' ); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); var f = document.createDocumentFragment(); while( div.childNodes.length ) f.appendChild( div.childNodes[0] ); noda.parentNode.replaceChild( f, noda ); }); }; |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
В IE ваш вариант выдал ошибку, т. к. коллекция .childNodes, почему то стала содержать undefined элементы. Можно исправить, подправив TextNode.each. Думаю, получается уже довольно продуманный вариант: var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0, length = childNodes.length; i < length; i++) { var I = childNodes[i]; if (I) I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { var f = document.createDocumentFragment(); do f.appendChild(div.firstChild); while (div.firstChild); noda.parentNode.replaceChild(f, noda); } }); }; Вместо .childNodes[0] можно использовать .firstChild Проверка if (div.firstChild && div.innerHTML != noda.nodeValue) { очень не лишняя, т. к. без нее будут перезаписываться и те ноды, что перезаписывать не надо, ну и как следствие while меняем на do-while, чтоб не было лишней проверки в цикле. |
Цитата:
Цитата:
Цитата:
p.s. считаю, вполне можно на ты ;-) |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>blank</title> <script type="text/javascript"> var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0, length = childNodes.length; i < length; i++) { var I = childNodes[i]; /*if (I) */I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; window.onload = function() { /*TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { var n = noda.nextSibling, p = noda.parentNode; do p.insertBefore(div.firstChild, n); while (div.firstChild); p.removeChild(noda); } }); */ TextNode.each(function(noda) { var div = document.createElement( 'div' ); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); var f = document.createDocumentFragment(); while( div.childNodes.length ) f.appendChild( div.childNodes[0] ); noda.parentNode.replaceChild( f, noda ); }); /*TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { var f = document.createDocumentFragment(); do f.appendChild(div.firstChild); while (div.firstChild); noda.parentNode.replaceChild(f, noda); } });*/ }; </script> </head> <body> <div class="authForm"> <form action="/Default.aspx" method="post" onsubmit="return $(this).validate();"> <input type="hidden" name="auth" value="auth" /> <br /> <div id="ctl00_Authorization1_messages"> <br /> </div> имя<br /> <input type="text" name="username" value="" maxlength="20" class="v-required v-name v-minlength2" /> <br /> пароль<br /> <input type="password" name="password" maxlength="40" class="v-required" /> <br /> <br /> <input type="submit" value=" Войти " /> <br /> <br /> </form> <a href="Registration.aspx">регистрация</a> <br /> <br /> </div> <table class="list"> <tr> <td> mmm </td> <td> dsfssssssss </td> <td> fdgfdgd f 111 http://www.youtube.com/watch?v=iuOcLoqo5e0 23423 rgfd </td> <td> 01.04.2009 1:32:11 </td> </tr> <tr> <td> sawewq </td> <td> django </td> <td> </td> <td> http://www.youtube.com/watch?v=iuOcLoqo5e0 </td> </tr> <tr> <td> asddddd </td> <td> django </td> <td> </td> <td> 30.03.2009 2:47:18 </td> </tr> </table> http://www.youtube.com/watch?v=iuOcLoqo5e0 </body> </html> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>blank</title> <script type="text/javascript"> var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0, length = childNodes.length; i < length; i++) { var I = childNodes[i]; /*if (I) */I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); var f = document.createDocumentFragment(); //if (div.firstChild) { while (div.firstChild) f.appendChild(div.firstChild); noda.parentNode.replaceChild(f, noda); //} }); /*TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { var f = document.createDocumentFragment(); do f.appendChild(div.firstChild); while (div.firstChild); noda.parentNode.replaceChild(f, noda); } });*/ }; </script> </head> <body> <form> <input type="text" /> <input type="text" /> </form> </body> </html> При этом если форму записать в одну линию, то ошибка исчезает: <form><input type="text" /><input type="text" /></form> |
значит удаляются (исключаются) пустые текстовые ноды, а length считается в начале цикла
upd: а точнее, во всех браузерах, кроме IE получаем 1: var div = document.createElement('div'); div.innerHTML = ' '; alert(div.childNodes.length); |
var f = document.createDocumentFragment(); while (div.firstChild) f.appendChild(div.firstChild); noda.parentNode.replaceChild(f, noda); а так как div пустой то и div.firstChild-а нету, т. е. содержимое while не разу не сработает. И потом нода заменяется на пустой DocumentFragment. Так в .childNodes попадают undefined. Решение: 1) В TextNode.each добавляем if (I) (в последнем моем посте он закоментирован) И не только для этого случая. Мало ли в каких ситуациях такое может случиться. 2) Зачем перезаписывать текстовые узлы содержащие пробельные символы. Добавляем проверку: if (div.firstChild) { (она тож закоментирована) В результате пустых div-ов просто не будет. 3) Зачем вообще перезаписывать текстовые узлы содержание которых не изменилось. Добавляем к проверке еще условие if (div.firstChild && div.innerHTML != noda.nodeValue) { В посте №20 был пока лучший вариант. |
Цитата:
Цитата:
Цитата:
я бы написал так: window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (! div.firstChild || (div.innerHTML == noda.nodeValue)) return; var f = document.createDocumentFragment(); while( div.firstChild ) f.appendChild( div.firstChild ); noda.parentNode.replaceChild( f, noda ); }); }; не знаю, если бы это была какая-то общедоступная библиотека, стоило бы ее как-то оптимизировать, но такого опыта у меня пока нету. И я бы скорее искал узкие места в реальных приложениях, чем оптимизировал все по максимуму кстати, по поводу читабельности можно вспомнить http://en.wikipedia.org/wiki/Unix_philosophy , там несколько раз отдается предпочтение читабельности, а не наоборот |
Цитата:
Цитата:
if (div.firstChild && div.innerHTML != noda.nodeValue) { и кода больше. |
Цитата:
Можно ее просто не запоминать: var TextNode = { each: function(callback, parent) { for (var childNodes = (parent || document.body).childNodes, i = 0; i < childNodes.length; i++) { var I = childNodes[i]; I.nodeType == 1 ? arguments.callee(callback, I) : I.nodeType == 3 && callback(I, i); } } }; |
Цитата:
Цитата:
|
Цитата:
Что касается window.onload, то это одноразовый код, минусы которого не будут перетекать с сайта на сайт. Так что, действительно, пусть себе тормозит сколько угодно. Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
if (! div.firstChild || (div.innerHTML == noda.nodeValue)) return; // более читабельным, чем такой: if (div.firstChild && div.innerHTML != noda.nodeValue) { // } Создается ощущение, что это уже предвзятое мнение, просто для того что бы быть несогласным со мной. Цитата:
Цитата:
var startTime = new Date(); for (var __i = 0; __i < 100001; __i++) { // } alert((new Date()) - startTime); И сравнивай сколько хочешь. Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
А по поводу твоих тестов, одни и те же операции во всех браузерах с одинаковой скоростью выполняются? А от версии к версии это меняется? Цитата:
|
if (div.firstChild && div.innerHTML != noda.nodeValue) { Бог с ней с читабельностью, а зачем это вообще нужно? |
давайте тогда свой текущий вариант приведу:
var TextNode = { each: function(callback, parent) { var childNodes = (parent || document.body).childNodes; length = childNodes.length; for (var i=0; i < length; i++) { var I = childNodes[i]; if( I.nodeType == 1 ) arguments.callee(callback, I); elseif( I.nodeType == 3 ) callback(I, i); } } }; window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (! div.firstChild || (div.innerHTML == noda.nodeValue)) return; var f = document.createDocumentFragment(); while (div.firstChild) f.appendChild(div.firstChild); noda.parentNode.replaceChild(f, noda); }); }; вариант Riimа, http://javascript.ru/forum/jquery/33...html#post16154 не считаю, что все должны писать как я, мне скорее интересно, действительно ли оправдана такая экономия на каждом операторе, пусть даже и в библиотеках div.firstChild: в ie div.innerHTML = ' '; ничего в div не добавляет, т.е. "пустые" текстовые ноды удаляются, при этом нужно в другом месте либо на каждой итерации проверять текущую длину (а не считать ее один раз), либо делать в итерации проверку, что теукщий узел существует, а именно здесь: div.innerHTML != noda.nodeValue: чтобы не выполнять лишних действий, когда текущий узел останется таким же каким и был |
Цитата:
Цитата:
Цитата:
Цитата:
Может моя экономия на спичках не так эффективна, как мне/тебе хотелось бы, но я хоть что-то стараюсь для этого делать. ---- Ну ладно, вот с этим: if (! div.firstChild || (div.innerHTML == noda.nodeValue)) return; еще можно мириться, но не менять while на do-while. Мне кажется, что любой хороший программист должен стараться избавлять логику программы от лишних действий. К тому же настолько очевидных. ---- Что касается авторитетных мнений, то ты сам сказал, что копаешься в Jquery. Там же всюду экономия на спичках, как в объеме кода так и в производительности. Чем тебе не авторитетное мнение. Возьми любой другой фреймворк кроме PrototypeJs. Везде это есть. И в PrototypeJs тоже есть, только у меня создалось впечатление, что автор сего творения, создавая метод, не задумывается над вопросом: "сжать его или ускорить?", и лепит первую оптимизацию, что придумалась. В результате часто методы, на которых половина фреймворка держится, оказываются, почему то сжаты, а там где можно было спокойно сжимать, явная оптимизация производительности. Вот и появляются те самые узкие места, которые теперь искать нужно. А ведь можно было сразу их исключить. В результате PrototypeJs самый тормозной фреймворк из известных, и чуть более сложные интерфейсы на его основе (lightbox например) тормозят значительно заметнее аналогичных на Jquery. |
Цитата:
|
Цитата:
Но речь не о том. Дальше что? Исправили. Нужно дальше оптимизировать? p.s. Riim, авторитеность jQuery сомнительна - http://javascript.ru/forum/offtopic/...html#post12621 |
Цитата:
Если видите ошибки, приводите свой вариант. Цитата:
Цитата:
|
Цитата:
window.onload = function() { TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); if (div.firstChild && div.innerHTML != noda.nodeValue) { alert('1'); } }); TextNode.each(function(noda) { var div = document.createElement('div'); div.innerHTML = noda.nodeValue.replace(/(http\:\/\/www\.youtube\.com\/watch\?v\=[0-9a-z]{11})/gi, '<a href="$1">$1</a>'); //if (div.firstChild && div.innerHTML != noda.nodeValue) { alert('2'); //} }); }; Только body получше заполните |
Часовой пояс GMT +3, время: 06:27. |