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

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


Часовой пояс GMT +3, время: 01:45.