Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Поиск выражения в тексте (https://javascript.ru/forum/jquery/3317-poisk-vyrazheniya-v-tekste.html)

grusha 06.04.2009 21:32

Поиск выражения в тексте
 
Есть текст в котором могут присутсвовать ссылки на 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.
http://www.youtube.com/watch?v=iuOcLoqo5e0

Вопрос в том как мне "отловить" эти ссылки. Ссылок может быть сколько угодно.
Думал отследить эти ссылки таким способом

jQuery('a[href~=youtube.com/watch?v=]')

Но проблема в том что атрибуда <a> нету у меня , есть просто текст.

Заранее благодарен.

Gvozd 06.04.2009 23:17

самый простой по логике способ:
получаем сисок всех нод с помощью getElementsByTagName('*')
перебираем их в цикле, а внутри цикла перебираем всех их потомков, являющихкся текстовыми нодами
каждый из них проверяемя на вхождение подстроки, и делаем с ним необходимое действие
меньше десятка строк, и никакого jQuery
на нем, же я не знаю как это реализовать, и есть ли для этого эффективные инструменты
я вроде бы слышал, что jQuery позволяет искать элементы использую XPath-синтаксис.

Riim 07.04.2009 03:55

<!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>

Gvozd 07.04.2009 10:54

Riim,
вы сами пытались запустить этот пример на странице большей, чем ваш тестовый пример? или вы считаете по несколько раз перерисовывать окно это хорошо?

Riim 07.04.2009 11:05

Если нужно их только найти то это вероятно лучший способ. Я просто забыл, что их еще и в тег "a" запихнуть надо. Невнимательно вопрос читал.

Riim 07.04.2009 11:24

Только вот у текстовых узлов innerHTML-а нету. И как поменять часть такого узла? Вероятно, придется брать его родителя и заменять часть через innerHTML. А этот родитель может тоже много чего содержать, и все это будет перерисовываться. Думаю, если другого способа нет, то лучше это на сервере делать. И ссылки будут рабочие до onload.

Gvozd 07.04.2009 15:31

Riim,
во первых, если даже считать, что мы ничего не можем сделать с текстовым узлом, а только с его родителем, это в разы лучше, чем перерисовывать ВЕСЬ документ.
вы-вторых, у текстовых нодов есть замечательное свойство nodeValue, которое доступно для редактирования.
помимо это есть куча замечательных методов типа inserBefore и прочих.
с их помощью много чего можно намутить, и при этом перерисовыватся будет минимум страницы
то есть только для проверки самого факта наличия ваш код подходит, и он быстрее.
для любой модификации в указанном месте, он уже не подходит

Riim 07.04.2009 15:42

>>> во первых, если даже считать, что мы ничего не можем сделать с текстовым узлом, а только с его родителем, это в разы лучше, чем перерисовывать ВЕСЬ документ.

Да я ж не спорю.

>>> для любой модификации в указанном месте, он уже не подходит

Если указанное место это див с текстом и без элементов.
Замечательно подойдет

Gvozd 07.04.2009 17:24

Цитата:

Сообщение от Riim
Если указанное место это див с текстом и без элементов.
Замечательно подойдет

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

Riim 07.04.2009 17:28

Про весь документ я и не спорю, а про указанное место ты сам начал.

Riim 07.04.2009 18:22

Попробовал 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>');
	});
};

Или я что то не так делаю?

Riim 07.04.2009 18:33

Получилось через 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);
	});
};

Gvozd 07.04.2009 19:55

Цитата:

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

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

я не уверен, насчет replaceChild и его кросбраузерности.
не проверял.
я лично в таком случае использовал insertBefore и removeChild
текстовые ноды могут быть не только у body-элемента.
они могут быть потомками любого тега, поэтому надо получить всю коллекцию, и для всех тегов перебрать, например

x-yuri 07.04.2009 23:08

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);

а еще, может, регулярное выражение можно проще сделать, но это зависит от наличия других ссылок в тексте

Riim 08.04.2009 05:53

Цитата:

Сообщение от Gvozd
я подразумевал, что задачу наиболее правильно с моей точки зрения решать перебором ...

подразумевал это, говоря фразу:
Цитата:

Сообщение от Gvozd
для любой модификации в указанном месте, он уже не подходит

именно ее я процитировал в посте выше, и, по-моему, она больше подразумевает то, что innerHTML плох для всех случаев (для любой модификации).

Цитата:

Сообщение от Gvozd
я не уверен, насчет replaceChild и его кроссбраузерности.

replaceChild описан в стандарте и есть даже в самых древних справочниках по dom. Если и будут какие-то проблемы, то они будут в каком-нибудь IE5.5, про который давно пора забыть.

Цитата:

Сообщение от Gvozd
я лично в таком случае использовал insertBefore и removeChild

Это и так вероятно далеко не самый быстрый вариант, а ты его еще замедлить хочешь (вызов двух методов вместо одного). Ну, станет он работать под каким-нибудь IE5.5 и 0,000....00.1 % пользователей будут рады, а вот остальные наоборот.

Цитата:

Сообщение от Gvozd
текстовые ноды могут быть не только у body-элемента

Как я понял не нравиться эта: (parent || document.body).childNodes строчка и ты предлагаешь пройтись еще и по meta-тегам.

Цитата:

Сообщение от Gvozd
они могут быть потомками любого тега, поэтому надо получить всю коллекцию

Рекурсивно обходиться ВСЯ коллекция.

Цитата:

Сообщение от x-yuri
а зачем ты div создаешь

С блочным элементом я поспешил, лучше span или font какой-нибудь, но элемент создавать все равно надо т. к. при создании текстового узла через createTextNode теги опять, же будут экранироваться. Если я что-то напутал, предлагай свой вариант.

Цитата:

Сообщение от x-yuri
я бы не записывал столько всего в for:
var childNodes = (parent || document.body).childNodes;
length = childNodes.length;
for (i = 0; i < length; i++) {

Теперь "i" будет в window. Еще пара таких функций и начнутся проблемы.

Цитата:

Сообщение от x-yuri
и использовал бы if'ы вместо тернарного оператора

Производительность от этого никак не измениться, зато добавится несколько байт кода. Если таких функций много, то эти несколько байт становятся несколькими Кб, и это уже неприятно.
Что касается читаемости, то, на мой взгляд, при нормальном оформлении тернарного оператора, он читается лучше, чем if-else.

Riim 08.04.2009 08:24

Цитата:

Сообщение от Riim
Если я что-то напутал, предлагай свой вариант.

Сам предлагаю:
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);
		}
	});
};


Теперь нет никаких лишних тегов.

Gvozd 08.04.2009 08:29

Цитата:

Сообщение от Riim
именно ее я процитировал в посте выше, и, по-моему, она больше подразумевает то, что innerHTML плох для всех случаев (для любой модификации).

да.
Цитата:

Сообщение от Riim
Это и так вероятно далеко не самый быстрый вариант, а ты его еще замедлить хочешь (вызов двух методов вместо одного). Ну, станет он работать под каким-нибудь IE5.5 и 0,000....00.1 % пользователей будут рады, а вот остальные наоборот.

я хотел сказать, лишь о моем конкретном незнании реализованных в DOM JS-а методах.теперь буду знать, что этот метод достаточно кросбраузерен для его использования.
Цитата:

Сообщение от Riim
Как я понял не нравиться эта: (parent || document.body).childNodes строчка и ты предлагаешь пройтись еще и по meta-тегам.

Цитата:

Сообщение от Riim
Рекурсивно обходиться ВСЯ коллекция.

пардон, тупанул.не увидел рекурсии потому что поверхностно осмотрел код.обхода body и его потомков считаю достаточным

Цитата:

Сообщение от Riim
Производительность от этого никак не измениться, зато добавится несколько байт кода. Если таких функций много, то эти несколько байт становятся несколькими Кб, и это уже неприятно.
Что касается читаемости, то, на мой взгляд, при нормальном оформлении тернарного оператора, он читается лучше, чем if-else.

вы лучше в процентах посчитайте насколько код увеличивается от использования нормальных условий.
ИМХО, незначительно.
более того это можно было бы назвать преждевременной оптимизацией, и потому подход этот вреден.
вам тернарный оператор нормально читается, а большинству нет.
то есть ваш подход приемлим, только если вы в одиночку пишите жестко инкапсулированый код, которй предполагаете никто кроме вас дорабатывать не должен.

Riim 08.04.2009 10:33

Цитата:

Сообщение от Gvozd
да.

Можно аргументировать. Возможно, у innerHTML действительно есть какие-то минусы, о которых я не знаю. И еще, в последнем, приведенном мною, коде (12:24) innerHTML тоже используется. Может, перепишете его без innerHTML. Интересно как это у вас получится. То есть я не говорю, что этого нельзя сделать, только вот кода на первый взгляд должно получиться раза в 3 больше, а о его производительности вообще лучше не думать.

Цитата:

Сообщение от Gvozd
вы лучше в процентах посчитайте насколько код увеличивается от использования нормальных условий.

Я считал. И не раз. Уменьшать код можно не только за счет тернарного оператора. Есть множество других способов.
У меня код уменьшается минимум на 15%. Думаете, я преувеличиваю? Нет, потому что на результат можно по-разному смотреть. Я, например, смотрю на него после работы YUICompressor-а. Считайте сами, каждая локальная переменная, например "parentNode", становиться одной буквой, то есть "parentNode" уменьшиться в 10 раз. В результате объем операторов в коде, в процентах, становиться довольно значительным и экономить на них уже довольно выгодно.

Цитата:

Сообщение от Gvozd
вам тернарный оператор нормально читается, а большинству нет

С одной стороны на вкус и цвет....
С другой, вот, попадется вам какой ни будь плагин к Jquery (а большинство из них пишутся примерно в этом же стиле) и будите с ним мучиться. У меня с этим проблем нет т. к. свободно воспринимаю самые разные стили.

Цитата:

Сообщение от Gvozd
если вы в одиночку пишите

Цитата:

Сообщение от Gvozd
никто кроме вас дорабатывать не должен

Смотря, что за код. Если это одноразовый код для одной странички, то мне все равно как он будет написан, я даже не думаю об этом, и в результате получается смесь разных стилей. Если мне скажут писать в таком то определенном стиле, то я и спорить не буду. А вот универсальный код, который выносится в отдельный файл, должен изначально писаться максимально качественно, так чтобы его доработка в идеале не потребовалась. И писаться он должен именно одним человеком. А остальные на его основе пишут одноразовые коды, и им должно быть все равно как написана основа, главное, что бы документация обновлялась вовремя.

x-yuri 08.04.2009 13:02

Цитата:

С блочным элементом я поспешил, лучше span или font какой-нибудь, но элемент создавать все равно надо т. к. при создании текстового узла через createTextNode теги опять, же будут экранироваться. Если я что-то напутал, предлагай свой вариант
не подумал
Цитата:

Теперь "i" будет в window. Еще пара таких функций и начнутся проблемы
пропустил
Цитата:

Производительность от этого никак не измениться, зато добавится несколько байт кода. Если таких функций много, то эти несколько байт становятся несколькими Кб, и это уже неприятно.
Что касается читаемости, то, на мой взгляд, при нормальном оформлении тернарного оператора, он читается лучше, чем if-else
мои соображения: читабельность; я считаю if'ы читабельнее в данном случае, а тернарный оператор, имхо, хорошо подходит для присваивания значений при не очень сложной логике, а не для вызова функций
Цитата:

С другой, вот, попадется вам какой ни будь плагин к Jquery (а большинство из них пишутся примерно в этом же стиле) и будите с ним мучиться
мучиться никто не будет
Цитата:

Смотря, что за код. Если это одноразовый код для одной странички, то мне все равно как он будет написан, я даже не думаю об этом, и в результате получается смесь разных стилей
а ТС не просил библиотеку/framework писать

мой вариант:
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 );
    });
};

Riim 08.04.2009 13:32

Цитата:

Сообщение от x-yuri
а тернарный оператор, имхо, хорошо подходит для присваивания значений при не очень сложной логике

Это не мешает ему применяться в других ситуациях.

Цитата:

Сообщение от x-yuri
мои соображения: читабельность

У каждого свои приоритеты.

Цитата:

Сообщение от x-yuri
мучиться никто не будет

Не зарекайтесь.

Цитата:

Сообщение от x-yuri
а ТС не просил библиотеку/framework писать

Разговор немного в сторону от темы ушел. И вы что-то друг за друга отвечаете. Прям наехали тут на меня вдвоем :)

Цитата:

Сообщение от x-yuri
мой вариант:

createDocumentFragment - классная штука. Не знал о ней.
В 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, чтоб не было лишней проверки в цикле.

x-yuri 08.04.2009 13:57

Цитата:

Не зарекайтесь
я периодически копаюсь в jQuery, проблем пока не было
Цитата:

И вы что то друг за друга отвечаете. Прям наехали тут на меня вдвоем
значит у нас просто совпадают мнения, зови своего одномышленника, похоливарим ;-)
Цитата:

В IE ваш вариант выдал ошибку, т. к. коллекция .childNodes почему то стала содержать undefined элементы
а можно содержимое body? А то на моих довольно простых данных не было проблем ни в ie6, ни в ie7. И неужели работа с childNodes напрямую (через n) решило эту проблему?
p.s. считаю, вполне можно на ты ;-)

Riim 08.04.2009 14:13

<!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>

Riim 08.04.2009 14:34

<!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>

x-yuri 08.04.2009 14:41

значит удаляются (исключаются) пустые текстовые ноды, а length считается в начале цикла
upd: а точнее, во всех браузерах, кроме IE получаем 1:
var div = document.createElement('div');
div.innerHTML = ' ';
alert(div.childNodes.length);

Riim 08.04.2009 15:07

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 был пока лучший вариант.

x-yuri 08.04.2009 15:51

Цитата:

Так в .childNodes попадают undefined
они туда не попадают, дело в уменьшении размера childNodes
Цитата:

И не только для этого случая.
Мало ли в каких ситуациях такое может случиться
с такими "как бы чего не вышло" можно далеко зайти, поэтому я предпочитаю знать, зачем я что-то делаю
Цитата:

Зачем перезаписывать текстовые узлы содержащие пробельные символы
это случайно получилось, я на это не рассчитывал
я бы написал так:
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 , там несколько раз отдается предпочтение читабельности, а не наоборот

Riim 08.04.2009 17:54

Цитата:

Сообщение от x-yuri
while( div.firstChild )
f.appendChild( div.firstChild );

Я уже писал, что в данном случае while нужно заменить на do-while, т. к. проверка div.firstChild происходит прямо перед циклом. Зачем делать ее 2 раза подряд.


Цитата:

Сообщение от x-yuri
if (! div.firstChild ||
(div.innerHTML == noda.nodeValue))
return;

медленней чем:
if (div.firstChild && div.innerHTML != noda.nodeValue) {


и кода больше.

Riim 08.04.2009 18:15

Цитата:

Сообщение от x-yuri
они туда не попадают, дело в уменьшении размера childNodes

Если точнее то да. Длинна уменьшается, а в цикле используется запомненная в переменной length длинна.
Можно ее просто не запоминать:
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);
		}
	}
};

x-yuri 08.04.2009 19:04

Цитата:

Я уже писал, что в данном случае while нужно заменить на do-while, т. к. проверка div.firstChild происходит прямо перед циклом. Зачем делать ее 2 раза подряд
я видел, я тоже уже писал, что у меня не производительность на первом месте. А если бы я оптимизировал, то искал бы скорее узкие места, а не экономил на спичках. По-крайней мере, я не видел авторитетных источников, которые бы проповедовали такое делать, зато видел много противоположных, один привел выше, т.е. там на самом деле даже несколько человек высказались за оптимизацию узких мест. Для меня был бы аргументом реальный проект, использующий именно эту функцию, который тормозит из-за того, что do-while был заменен на while
Цитата:

медленней чем...и кода больше
зато нету лишнего уровня вложенности

Riim 08.04.2009 19:31

Цитата:

Сообщение от x-yuri
А если бы я оптимизировал, то искал бы скорее узкие места, а не экономил на спичках.

Универсальные функции обычно и становятся узкими местами. Не лучше ли подумать об этом сразу, чем возвращаться потом.
Что касается window.onload, то это одноразовый код, минусы которого не будут перетекать с сайта на сайт. Так что, действительно, пусть себе тормозит сколько угодно.

Цитата:

Сообщение от x-yuri
зато нету лишнего уровня вложенности

А чем плох лишний уровень вложенности? Ты же за читаемость.

Цитата:

Сообщение от x-yuri
который тормозит из-за того, что do-while был заменен на while

Из-за одного такого случая вряд ли что-то изменится. Но если весь код писать так, то меняется, и очень даже заметно.

Цитата:

Сообщение от x-yuri
Для меня был бы аргументом реальный проект

Я вот только что был на qip.ru. У меня почта там. Зайди и посмотри, как тормозит почтовый интерфейс напичканный ajax-ом. При нажатии на ссылку запускающую javascript аж флеш-банеры подвисают. А теперь зайди на gmail.

x-yuri 08.04.2009 20:16

Цитата:

Универсальные функции обычно и становятся узкими местами. Не лучше ли подумать об этом сразу, чем возвращаться потом
нет, потому что заранее неизвестно, где будет узкое место. И вместо оптимизации всего кода, нужно оптимизировать конкретные места. А вообще, как сказал один чувак "если ты привык к такому стилю и можешь при этом эффективно заниматься проектом, то отлично. Пока кому-то другому не прийдется его отлаживать". Т.е. плюс в производительности (а это еще надо доказать на реальном проекте, мне вот так сходу не очевидно), но минус в сложностях поддержки проекта
Цитата:

А чем плох лишний уровень вложенности? Ты же за читаемость.
тем что он лишний и это как раз про читабельность
Цитата:

Из-за одного такого случая вряд ли что-то изменится. Но если весь код писать так, то меняется, и очень даже заметно
это все теория, нужен реальный (т.е. не теоретический) проект/страничка, выполненные, например, мной и тобой, на котором можно было бы сравнить производительность. Или может у тебя есть результаты подобных тестов, или статьи известных авторов на тему
Цитата:

Я вот только что был на qip.ru. У меня почта там. Зайди и посмотри, как тормозит почтовый интерфейс напичканный ajax-ом. При нажатии на ссылку запускающую javascript аж флеш-банеры подвисают. А теперь зайди на gmail
1) это ничего не говорит про экономию на операторах, это говорит только о том, что gmail сделан лучше, а в чем именно причина - неизвестно 2) это довольно серьезные сервисы (для большинства сайтов не думаю, что ты заметишь свои оптимизации, разве что отдельные в отдельных местах) и для таких проектов вряд ли оправдано использование популярных фреймворков

Riim 08.04.2009 21:19

Цитата:

Сообщение от x-yuri
нет, потому что заранее неизвестно, где будет узкое место

Любая универсальная функция, это уже 100% узкое место, как бы идеально она не была оптимизирована, т. к. неизвестно заранее где она найдет себе применение. А рано или поздно она найдет себе применение в месте, где требуется высокая производительность. И тогда появится необходимость открыть ее и подумать над тем, как бы ускорить ее еще хоть на чуть-чуть. И тут уже даже экономия на спичках окажется эффективна. Зачем откладывать эту работу на потом, когда будут сроки.

Цитата:

Сообщение от x-yuri
но минус в сложностях поддержки проекта

Для того кто будет работать с моим кодом может и так(если у него мало опыта). Для меня же это скорее плюс, т. к. я сильнее привязываю к себе заказчика. Студент Вася, помучившись недельку с "этим странным javascript-ом", откажется от работы, и позвонят опять мне. Я не говорю, что нужно специально писать запутанно, но и беспокоиться о Васе в ущерб себе не нужно. А при работе в группе заранее обговариваются правила оформления кода. И раз мне платят за какой-то определенный стиль, то и вопросов нет.

Цитата:

Сообщение от x-yuri
тем что он лишний и это как раз про читабельность

Я уже совсем запутался. При всем своем желании, я не могу признать такой код:
if (! div.firstChild ||
            (div.innerHTML == noda.nodeValue))
                return;
//

более читабельным, чем такой:
if (div.firstChild && div.innerHTML != noda.nodeValue) {
    //
}


Создается ощущение, что это уже предвзятое мнение, просто для того что бы быть несогласным со мной.

Цитата:

Сообщение от x-yuri
нужен реальный (т.е. не теоретический) проект/страничка, выполненные, например, мной и тобой

Я же привел ссылки. Или теперь уже нужно что бы это были не чьи то сайты. А потом что понадобится?


Цитата:

Сообщение от x-yuri
на котором можно было бы сравнить производительность

Неужели так трудно написать:
var startTime = new Date();
for (var __i = 0; __i < 100001; __i++) {
	//
}
alert((new Date()) - startTime);

И сравнивай сколько хочешь.

Цитата:

Сообщение от x-yuri
Или может у тебя есть результаты подобных тестов

Три 48-листовые тетради исписаны результатами.

Цитата:

Сообщение от x-yuri
а в чем именно причина - неизвестно

По моему очевидно, что в кривом javascript-е.

x-yuri 08.04.2009 22:21

Цитата:

Создается ощущение, что это уже предвзятое мнение, просто для того что бы быть несогласным со мной
ни в коем случае, например, вот здесь. Могу еще поискать источники

Цитата:

Я же привел ссылки. Или теперь уже нужно что бы это были не чьи то сайты. А потом что понадобится?
у меня нету доступа ни к google-, ни к qip-серверам. Я не могу переписать ни одну из их страничек и сравнить разницу в производительности

Цитата:

Неужели так трудно написать:
var startTime = new Date();
for (var __i = 0; __i < 100001; __i++) {
//
}
alert((new Date()) - startTime);
И сравнивай сколько хочешь
не трудно, но у меня пока такой необходимости не возникало. Т.е. когда тормоза были из-за js. А причин сравнивать производительность отдельных операторов не вижу смысла пока. Вижу причины искать узкие места, но ты такую деятельность похоже полностью исключаешь. Но откуда тогда взялось это выражение?

А по поводу твоих тестов, одни и те же операции во всех браузерах с одинаковой скоростью выполняются? А от версии к версии это меняется?

Цитата:

По моему очевидно, что в кривом javascript-е
только не понятно, изменит что-то запись всех переменных в одном var, for, преобразование while -> do-while etc

Zeroglif 08.04.2009 23:33

if (div.firstChild && div.innerHTML != noda.nodeValue) {


Бог с ней с читабельностью, а зачем это вообще нужно?

x-yuri 09.04.2009 03:55

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

Riim 09.04.2009 07:03

Цитата:

Сообщение от x-yuri
браузерах с одинаковой скоростью выполняются? А от версии к версии это меняется?

Вот потому тетрадей 3, а не 1. Все меняется, но соотношение очень редко. Если одна операция в 2 раза медленней в одном браузере, то 95% она будет медленней и в других. И в следующих версиях тоже.

Цитата:

Сообщение от x-yuri
А причин сравнивать производительность отдельных операторов не вижу смысла пока. Вижу причины искать узкие места, но ты такую деятельность похоже полностью исключаешь

Нет, не исключаю. Просто у меня нет необходимости в ней. Зная производительность каждого оператора, можно писать функцию и параллельно просчитывать ее производительность. Дальше сразу ясно, где и когда она станет узким местом. И когда это случится, сразу будет ясно в каком направлении копать.

Цитата:

Сообщение от x-yuri
только не понятно, изменит что-то запись всех переменных в одном var, for, преобразование while -> do-while

Я уже писал, что из-за одного случая ничего не изменится. Нужно стараться ВСЕ писать как можно лучше.

Цитата:

Сообщение от x-yuri
у меня нету доступа ни к google-, ни к qip-серверам

И теперь можно писать, как вздумается? По-моему нужно стараться становиться лучшим программистом, чем есть.
Может моя экономия на спичках не так эффективна, как мне/тебе хотелось бы, но я хоть что-то стараюсь для этого делать.

----

Ну ладно, вот с этим:
if (! div.firstChild ||
            (div.innerHTML == noda.nodeValue))
                return;

еще можно мириться, но не менять while на do-while. Мне кажется, что любой хороший программист должен стараться избавлять логику программы от лишних действий. К тому же настолько очевидных.

----

Что касается авторитетных мнений, то ты сам сказал, что копаешься в Jquery. Там же всюду экономия на спичках, как в объеме кода так и в производительности. Чем тебе не авторитетное мнение.
Возьми любой другой фреймворк кроме PrototypeJs. Везде это есть. И в PrototypeJs тоже есть, только у меня создалось впечатление, что автор сего творения, создавая метод, не задумывается над вопросом: "сжать его или ускорить?", и лепит первую оптимизацию, что придумалась. В результате часто методы, на которых половина фреймворка держится, оказываются, почему то сжаты, а там где можно было спокойно сжимать, явная оптимизация производительности. Вот и появляются те самые узкие места, которые теперь искать нужно. А ведь можно было сразу их исключить. В результате PrototypeJs самый тормозной фреймворк из известных, и чуть более сложные интерфейсы на его основе (lightbox например) тормозят значительно заметнее аналогичных на Jquery.

Zeroglif 09.04.2009 08:29

Цитата:

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

Поэтому для каждой! ноды вы создаёте элемент и так далее. Я задал выше вопрос, неужто никто не видит, что до разговора о спичках, нужно ошибки логики устранить... ;)

x-yuri 09.04.2009 08:38

Цитата:

поэтому для каждой! ноды вы создаёте элемент и так далее. Я задал выше вопрос, неужто никто не видит, что до разговора о спичках, нужно ошибки логики устранить...
то, что можно один раз создавать div и DocumentFragment? Да (собственно, идея Dmitry A. Soshnikov) И это скорее оптимизация, чем ошибка логики
Но речь не о том. Дальше что? Исправили. Нужно дальше оптимизировать?
p.s. Riim, авторитеность jQuery сомнительна - http://javascript.ru/forum/offtopic/...html#post12621

Riim 09.04.2009 08:40

Цитата:

Сообщение от Zeroglif
что до разговора о спичках, нужно ошибки логики устранить

Похоже вы сами еще не до конца разобрались в логике кода.
Если видите ошибки, приводите свой вариант.

Цитата:

Сообщение от Zeroglif
Поэтому для каждой! ноды вы создаёте элемент и так далее

Можно и без этого обойтись. Я спорю на тему "как оптимизировать код" на примере window.onload, но это плохой пример т. к. это одноразовый код. Я уже писал что мне все равно как он оптимизирован. Я просто взял несколько моментов из него как примеры.

Цитата:

Сообщение от Zeroglif
Я задал выше вопрос, неужто никто не видит

x-yuri вам ответил на него. В постах выше я 2 раза пояснял эту строку. Читайте внимательней.

Riim 09.04.2009 08:43

Цитата:

Сообщение от Riim
x-yuri вам ответил на него. В постах выше я 2 раза пояснял эту строку. Читайте внимательней.

Если все равно не понятно, запустите:

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, время: 08:18.