2010-06-07 2 views
3

Я работаю над одной задачей, чтобы извлечь тег заголовка из данного нормального текста (это не HTML DOM). У меня есть ниже тех случаях, когда нужно извлечь тег заголовка (ы):Извлечь теги заголовков из обычного текста

Случай 1:

<html> 
<head> 
      <title>Title of the document</title> 
</head> 
<body> 
The content of the document...... 
</body> 
</html> 

Ожидаемое: Название документа

Случай 2:

<html> 
<head> 
      <title>Title of the document</title> 
      <title>Continuing title</title> 
</head> 
<body> 
The content of the document...... 
</body> 
</html> 

Ожидаемые: Названия документа Продолжает заголовок

Случай 3 (Вложенные теги заголовков)

<html> 
<head> 
      <title>Title of the document 
      <title>Continuing title</title></title> 
</head> 
<body> 
The content of the document...... 
</body> 
</html> 

Ожидаемый: Названия документа Продолжает заголовок

Я хотел извлекать теги заголовка, используя регулярное выражение в javascript. Reg-ex должен работать в этом случае.

Кто-нибудь знает о this..please, дайте мне знать ... Заранее спасибо

+2

Регулярное выражение и неверный HTML радуются. – kennytm

+0

Это не теги названия, а названия * elements *. См. Http://perfectionkills.com/tag-is-not-an-element-or-is-it/ –

+0

Ну, так как это не совсем HTML, он может называть его любым способом :-) – RoToRa

ответ

1

Это решение этой конкретной задачи с помощью этого сломанный «псевдо-HTML». Это не относится к обычной HTML:

function extractTitle(text) { 
    var m = /<title>(.*)<\/title>/.exec(text); 
    if (m && m[1]) { 
    return m[1].replace(/<\/?title>/g," ").replace(/\s+/," "); 
    } 
    return; // returns undefined 
} 
+0

Это работает, но во втором примере пробел между тегом закрытия и открытия заголовка не изменяется; например, в этом случае будет возвращено много пробелов, но если теги будут написаны рядом друг с другом, результатом будет: «Название документа« Продолжающееся название ». –

+0

@Marcel: Верно. Я заменил теги пробелом и добавлю замену, которая сворачивает все пробелы в одно пространство. – RoToRa

2

Don't parse HTML with regexen! Серьезно, это практически невозможно в общем случае. И на самом деле вы не можете делать то, что хотите, с помощью regexen. Это та же проблема, что и сопоставление сбалансированных вложенных пар круглых скобок, за исключением того, что вы хотите сопоставить вложенные пары <title>/</title>, и это не обычный язык.

(Edit 1:. мне пришлось пересмотреть свой ответ, так как я видел, что вы не имели доступа к DOM, для того, что я изначально имел, смотри ниже)

Итак, почему вам нужно сделать это? Возможно, есть лучший способ. Это помеченный JavaScript, но вы никогда не упоминаете об этом в своем ответе. Если вы не находитесь в JavaScript, возможно, вы можете использовать парсер HTML, который, вероятно, будет лучшим выбором. Если вы находитесь в JavaScript, все равно может быть, но я не гуру JavaScript.

Теперь, примечание: наличие нескольких или вложенных тегов title на самом деле не является законным HTML, поэтому вам необходимо не должно. Если это так, и если мы сможем сделать еще несколько предположений, вы можете построить пример использования, который, вероятно, будет работать. Например: нет комментариев, нет CDATA блоков и т. Д. (Хотя вы можете справиться с ними, потому что они не могут вложить.) Но могут быть случаи краев, которые я забываю! Кроме того, ни Safari, ни Firefox не рассматривали ваш третий случай как вложенные теги заголовков, а рассматривали его как один тег заголовка, содержащий литеральную строку Title of the document <title> Continuing title. Таким образом, если вы можете проигнорировать этот случай, то можно было бы обмануть хрупкий набор регулярных выражений, который мог бы работать с может. Возможно (слегка проверенный!) Что-то вроде этого:

// Edit 2: Made this function case-insensitive where it needed to be. 
// Edit 3: Used substring() instead of replace() to remove the extraneous 
//   title tags and fixed the "not matching" case. 
function getTitle(html) { 
    return (html.replace(/<!\[CDATA\[(.+?)\]\]>/g 
         , function (_match, body) { 
          return body.replace(/&/g, '&amp;') 
            .replace(/</g, '&lt;') 
            .replace(/>/g, '&gt;') 
         }) 
       .replace(/<!--.+?-->/g, '') 
       .match(/<title>.+?<\/title>/ig) || []) 
       .map(function (t) { return t.substring(7, t.length - 8) }) 
       .join(' ') 
} 

Я не гуру HTML, так что я, вероятно, пропустил пару крайние случаи, но вот то, что это делает. Сначала мы находим каждый CDATA section. Мы берем его внутренности и превращаем каждый незаконный персонаж в его эквивалент сущности и избавляемся от <![CDATA[ и ]]>. Затем мы удаляем каждый комментарий. После этого мы сопоставляем каждый заголовок и получаем массив совпадений (получение массива совпадений несовместимо с извлечением подгрупп), если мы находимся в случае с недопустимым-множественным title. Редактировать 3: Затем мы проверяем, нет ли совпадений, и в этом случае .match() возвращает null и вместо этого возвращает [], если это так; таким образом, у нас всегда есть массив. Затем мы обрезаем теги с начала и конца (edit 3: больше не используем regexen для этого шага) и, наконец, строим каждый фрагмент заголовка вместе с пробелом. Это будет обрабатывать, я думаю, ваш случай один и кейс 2. Если вам нужен только судебный иск (случай один), замените последние три строки (кроме }) одной строкой .match(/<title>(.+?)<\/title>/)[0]. Однако, хотя во многих случаях это будет работать (я думаю), я делаю предположения (как о нашем вводе (, например, так и теги заголовка отображаются вместе и где вы их хотите) и о том, что мы ищем один (набор) <title>...</title> s) и, возможно, пропустил какой-то крайный кейс или другой. Будем надеяться, что вы сможете использовать более приятное решение.


Edit 1: я пропустил тот факт, что вам нужно работать над открытым текстом; остальная часть моего первоначального ответа предполагала, что у вас есть доступ к DOM. Я оставлю его здесь для потомков, но это не особенно важно для вас.

Если вы имели доступ к DOM в JavaScript, вы можете сделать следующее, если вы имели надлежащего HTML с одним title тег:

var titles = document.getElementsByTagName('title') 
var titleText = titles.length > 0 ? titles[0].text : '' 

Однако, если вы на самом деле HTML, который выглядит как вторые два случая вы показали нам (надеюсь, нет, но вы никогда не знаете), тогда вам придется сделать что-то еще. Ни Firefox, ни Safari не рассматривали ваш третий случай как вложенные теги заголовков, вместо этого рассматривали его как один тег заголовка, содержащий литеральную строку Title of the document <title> Continuing title. Таким образом, если иметь дело только с первыми двумя случаями, это будет работать:

var titles = document.getElementsByTagName('title') 
var tlength = titles.length 
var titleText = '' 
for (var i = 0; i < tlength; ++i) 
    titleText += titles[i].text 

И если у вас есть третий случай, то, что вам нужно сделать, это удалить посторонний <title> тега, который мог быть немного сложным, но, вероятно, нет. Если вы знаете, что <title> никогда не будет отображаться, кроме как из-за искаженного HTML, как описано выше, вы можете использовать метод replace, чтобы избавиться от него. В одной standalone- <title>, случай, вы хотите

// Edit 2: Case-insensitivity 
var titles = document.getElementsByTagName('title') 
var titleText = titles.length > 0 ? titles[0].text.replace(/<title>/ig,'') : '' 

В искаженной нескольких standalone- <title> случае, вы хотите

// Edit 2: Case-insensitivity 
var titles = document.getElementsByTagName('title') 
var tlength = titles.length 
var titleText = '' 
for (var i = 0; i < tlength; ++i) 
    titleText += titles[i].text.replace(/<title>/ig,'') 

Если <title> может произойти в правильной строки и по другим причинам, однако, у вас проблемы; вам нужно было бы найти , почему он был в строке и только заменил его, если бы вы предполагались. И, насколько я могу судить, нет хорошего общего способа сделать это. Но, надеюсь (хотя и не обязательно), у вас есть законный HTML.

+1

Хотя это (очень) хороший ответ, я не думаю, что это соответствует потребностям OP, поскольку он заявил: «Измените название тега [sic!] Из данного нормального текста (это не HTML DOM)». I думаю, что он действительно хочет разобрать простой текст, а не извлекать элементы заголовка из DOM. –

+1

* D'oh *, я пропустил это. Хорошо, я оставлю это здесь - первая часть по-прежнему актуальна, поскольку на самом деле это невозможно с помощью regexen. –

+0

Хорошо, я добавил что-то, что действительно может быть релевантным *. –

Смежные вопросы