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, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
})
.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.
Регулярное выражение и неверный HTML радуются. – kennytm
Это не теги названия, а названия * elements *. См. Http://perfectionkills.com/tag-is-not-an-element-or-is-it/ –
Ну, так как это не совсем HTML, он может называть его любым способом :-) – RoToRa