Поиск выражения в тексте
Есть текст в котором могут присутсвовать ссылки на 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, время: 14:35. |