Есть ли простой способ конвертировать HTML с несколькими тегами <br/> в правильные окружающие теги<p>в Javascript?
Допустим, у меня есть куча HTML, как показано ниже:
bla bla bla long paragraph here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>
Есть ли простой способ с Javascript, чтобы преобразовать его в правильно семантическую <p>
теги? Например:
<p>
bla bla bla long paragraph here
</p>
<p>
bla bla bla more paragraph text
</p>
Интервал вывода не важен, в идеале он будет работать с любым интервалом ввода.
Я думаю, что я мог бы попытаться приготовить регулярное выражение, но прежде чем я это сделаю, я хотел убедиться, что я: а) избегаю мира зла и б) не было ничего другого - я пытался сделать поиск в Google, но еще ничего не придумали.
Спасибо за любой совет!
4 ответа
Мне стало скучно. Я уверен, что необходимы оптимизации / твики. Использует немного JQuery, чтобы сделать свою магию. Работал в FF3. И ответ на ваш вопрос заключается в том, что не очень "простой" способ:)
$(function() {
$.fn.pmaker = function() {
var brs = 0;
var nodes = [];
function makeP()
{
// only bother doing this if we have nodes to stick into a P
if (nodes.length) {
var p = $("<p/>");
p.insertBefore(nodes[0]); // insert a new P before the content
p.append(nodes); // add the children
nodes = [];
}
brs=0;
}
this.contents().each(function() {
if (this.nodeType == 3) // text node
{
// if the text has non whitespace - reset the BR counter
if (/\S+/.test(this.data)) {
nodes.push(this);
brs = 0;
}
} else if (this.nodeType == 1) {
if (/br/i.test(this.tagName)) {
if (++brs == 2) {
$(this).remove(); // remove this BR from the dom
$(nodes.pop()).remove(); // delete the previous BR from the array and the DOM
makeP();
} else {
nodes.push(this);
}
} else if (/^(?:p)$/i.test(this.tagName)) {
// these tags for the P break but dont scan within
makeP();
} else if (/^(?:div)$/i.test(this.tagName)) {
// force a P break and scan within
makeP();
$(this).pmaker();
} else {
brs = 0; // some other tag - reset brs.
nodes.push(this); // add the node
// specific nodes to not peek inside of - inline tags
if (!(/^(?:b|i|strong|em|span|u)$/i.test(this.tagName))) {
$(this).pmaker(); // peek inside for P needs
}
}
}
});
while ((brs--)>0) { // remove any extra BR's at the end
$(nodes.pop()).remove();
}
makeP();
return this;
};
// run it against something:
$(function(){
$("#worker").pmaker();
});
И это была HTML-часть, с которой я тестировал:
<div id="worker">
bla bla bla long <b>paragraph</b> here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>
this text should end up in a P
<div class='test'>
and so should this
<br/>
<br/>
and this<br/>without breaking at the single BR
</div>
and then we have the a "buggy" clause
<p>
fear the real P!
</p>
and a trailing br<br/>
</div>
И результат:
<div id="worker"><p>
bla bla bla long <b>paragraph</b> here
</p>
<p>
bla bla bla more paragraph text
</p>
<p>
this text should end up in a P
</p><div class="test"><p>
and so should this
</p>
<p>
and this<br/>without breaking at the single BR
</p></div><p>
and then we have the a "buggy" clause
</p><p>
fear the real P!
</p><p>
and a trailing br</p>
</div>
Сканирование каждого из дочерних элементов + текст включающего элемента. Каждый раз, когда вы сталкиваетесь с элементом "br", создайте элемент "p" и добавьте к нему все находящиеся на рассмотрении вещи. Вспенить, промыть, повторить.
Не забудьте удалить материал, который вы перемещаете в новый элемент "p".
Я обнаружил, что эта библиотека (prototype.js) полезна для такого рода вещей.
Я предполагаю, что вы на самом деле не разрешаете другие. Иногда вам нужно сохранять одиночные переносы строк (не все <br />
элементы плохие), и вы хотите только включить двойные экземпляры <br />
в абзацы разрывы.
При этом я бы:
- Удалить все разрывы строк
- Оберните всю партию в абзац
- замещать
<br /><br />
с</p>\n<p>
- Наконец, удалите все пустые
<p></p>
элементы, которые могли быть сгенерированы
Таким образом, код может выглядеть примерно так:
var ConvertToParagraphs = function(text) {
var lineBreaksRemoved = text.replace(/\n/g, "");
var wrappedInParagraphs = "<p>" + lineBreaksRemoved + "</p>";
var brsRemoved = wrappedInParagraphs.replace(/<br[^>]*>[\s]*<br[^>]*>/gi, "</p>\n<p>");
var emptyParagraphsRemoved = brsRemoved.replace(/<p><\/p>/g, "");
return emptyParagraphsRemoved;
}
Примечание: я был очень многословен, чтобы показать процессы, вы бы, конечно, упростили его.
Это превращает ваш образец:
bla bla bla long paragraph here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>
В:
<p>bla bla bla long paragraph here</p>
<p>bla bla bla more paragraph text</p>
Но это происходит без удаления каких-либо <br />
элементы, которые вы можете на самом деле хотите.
Я бы сделал это в несколько этапов:
- RegExp: конвертировать все br-тэги в переводы строк.
- RegExp: убрать все пробелы.
- RegExp: преобразовать несколько разрывов строк в единичные.
- Используйте Array.split('\n') для результата.
Это должно дать массив со всеми "реальными" параграфами (теоретически). Затем вы можете просто пройти по нему и обернуть каждую строку в p-теги.