从普通文本中提取标题标签

时间:2010-06-07 08:39:25

标签: javascript regex

我正在处理一项任务,从给定的普通文本中提取标题标签(它不是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应适用于上述情况。

有谁知道这个..请告诉我... 在此先感谢

2 个答案:

答案 0 :(得分:2)

Don't parse HTML with regexen!说真的,在一般情况下,这几乎是不可能的。事实上,你不能用regexen做你想做的事。这与匹配平衡嵌套的括号对相同,除了您想要匹配嵌套的<title> / </title>对,并且这不是常规语言。

编辑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,如果是这种情况,则返回[];这样,我们总有一个数组。然后我们从开头和结尾修剪标签(编辑3:不再使用regexen进行此步骤),最后将每个标题片段与空格一起串起来。这将处理,我认为,您的案例一和案例二。如果您只需要法律案例(案例一),请用单行}替换最后三行(.match(/<title>(.+?)<\/title>/)[0]除外)。然而,尽管在许多情况下这会起作用(我认为),但我做了一些假设(关于我们的输入(例如,标题标签都出现在一起以及你想要它们的位置)以及我们的事实'只寻找一个(一组)<title>...</title> s并且可能错过了一些边缘情况或其他情况。希望结果是你可以使用更好的解决方案。


编辑1:我错过了你需要处理纯文本的事实;我的原始答案的其余部分假设您可以访问DOM。我会把它留给后人,但它与你并不特别相关。

如果您可以使用JavaScript访问DOM,那么如果您使用带有title个标记的正确HTML,则可以执行以下操作:

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方法来摆脱它。在单机版 - <title>中,您需要

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

在格式错误的多个独立 - <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 :(得分: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
}