我正在处理一项任务,从给定的普通文本中提取标题标签(它不是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应适用于上述情况。
有谁知道这个..请告诉我... 在此先感谢
答案 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, '&')
.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
,如果是这种情况,则返回[]
;这样,我们总有一个数组。然后我们从开头和结尾修剪标签(编辑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
}