我正在创建一个将URL作为输入的应用程序,从网络上检索页面的HTML内容并提取 标签中不包含的一切. 。换句话说,该页面的访问者可以看到页面的文本内容。其中包括“掩盖”所有封装的一切 <script></script>, <style></style><!-- -->, ,由于这些部分包含未包裹在标签中的文本(但最好是单独使用)。

我已经构造了这个正则:

(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>)

它正确选择了我要忽略的所有内容,并且只剩下页面的文本内容。但是,这意味着我要提取的内容不会在比赛集合中显示(我正在Visual Studio 2010中使用VB.NET)。

是否有一种方法可以“反转”这样的整个文档的匹配,以便我可以在上述正则匹配中忽略的所有文本字符串上匹配?

到目前为止,我所做的是在末尾添加另一个替代方案,该替代方法选择“任何不包含<或>的序列”,这意味着剩余的文本。我在一个捕获组中命名了最后一个位,当我迭代比赛时,我检查了“文本”组中是否存在文本。这起作用了,但是我想知道是否可以通过Regex和 只是 最终在纯文本上进行匹配。

这应该一般起作用,而不知道HTML中的任何特定标签。应该提取 全部 文本。此外,我需要保留原始的HTML,以便页面保留其所有链接和脚本 - 我只需要能够提取文本,以便我可以在其中执行搜索和替换,而不必担心“重命名”任何标签,属性,属性或脚本变量等(因此,我不能在所有的比赛中做任何“无替换”,因为即使我剩下我的需求,也要将其重新插入回到正确的位置,这很麻烦功能齐全的文档)。

我想知道是否可以使用Regex(我知道HTML Agility Pack和XPath,但不喜欢)。

有什么建议么?

更新:这是我最终得到的(基于正则的)解决方案: http://www.martinwardener.com/regex/, ,在演示Web应用程序中实现,该应用程序将显示Active Regex字符串以及测试引擎,该引擎使您可以在任何在线HTML页面上运行解析,从以及在完整的HTML文档中突出显示所有正则匹配的视图)。

有帮助吗?

解决方案 5

好,所以这就是我的做法:

使用我的原始正则(添加了纯文本的搜索模式),这恰好是标签搜索完成后剩下的任何文本):

(?:(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?P<text>[^<>]*)

然后在vb.net中:

Dim regexText As New Regex("(?:(?:<(?<tag>script|style)[\s\S]*?</\k<tag>>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?<text>[^<>]*)", RegexOptions.IgnoreCase)
Dim source As String = File.ReadAllText("html.txt")
Dim evaluator As New MatchEvaluator(AddressOf MatchEvalFunction)
Dim newHtml As String = regexText.Replace(source, evaluator)

文本的实际替换在这里发生:

Private Function MatchEvalFunction(ByVal match As Match) As String
    Dim plainText As String = match.Groups("text").Value
    If plainText IsNot Nothing AndAlso plainText <> "" Then
        MatchEvalFunction = match.Value.Replace(plainText, plainText.Replace("Original word", "Replacement word"))
    Else
        MatchEvalFunction = match.Value
    End If
End Function

瞧。 newHtml 现在包含原始的精确副本,除了页面中的每一次“原始单词”(如浏览器中显示)都用“替换单词”进行切换,并且所有HTML和脚本代码均未触及。当然,可以 /可以 /可以更精细的替代程序,但这表明了基本原则。这是12行代码,包括函数声明和HTML代码等的加载。我对看到并行解决方案非常感兴趣,在DOM等中完成(是的)(是的,我知道可以通过 肯定 某些嵌套标签怪癖的出现 - 在脚本重写中 - 但是,如果有的话,损坏仍然非常有限(请参阅上面的某些评论),总的来说,这将很好地完成这项工作)。

其他提示

我所做的是最后添加另一个替代方案,以选择“不包含的任何序列 < 或者 >”,这意味着剩余的文字。我在捕获组中命名了最后一个位,当我迭代匹配项时,我检查了“文本”组中是否存在文本。

那就是通常会做的。甚至更简单,用和空字符串替换标记模式的每场比赛,而您剩下的就是您要寻找的东西。

这是有效的,但是这里和那里似乎有一根弦,不应该被捡起。

好吧,那是因为您的表情以及一般而言是不足以解析有效的HTML,更不用说真正网络上出现的恐怖了。要查看的第一个提示,如果您真的想追逐这种徒劳的方法:属性值(以及通常的文本内容)可能包含一个unscaped > 特点。

我想再次提出HTML敏捷包的好处。

ETA:由于您似乎想要它,所以这里有一些标记的示例,看起来像是您的表达方式。

<a href=link></a> - unquoted
<a href= link></a> - unquoted, space at front matched but then required at back
<a href="~/link"></a> - very common URL char missing in group
<a href="link$!*'link"></a> - more URL chars missing in group
<a href=lïnk></a> - IRI
<a href
    ="link"> - newline (or tab)
<div style="background-image: url(link);"> - unquoted
<div style="background-image: url( 'link' );"> - spaced
<div style="background-image: u&#114;l('link');"> - html escape
<div style="background-image: ur\l('link');"> - css escape
<div style="background-image: url('link\')link');"> - css escape
<div style="background-image: url(\
'link')"> - CSS folding
<div style="background-image: url
('link')"> - newline (or tab)

这只是完全有效的标记 惯于 匹配正确的链接,没有任何可能的无效标记,不应该匹配链接的标记,或者与您从文本分配标记的其他技术中的许多问题中的任何一个。这是冰山一角。

Regex对于检索HTML文档的文本内容并不可靠。正则无法处理嵌套标签。假设文档不包含任何嵌套标签,Regex仍然需要每个标签都正确关闭。

如果您使用的是PHP,为简单起见,我强烈建议您使用DOM(文档对象模型)来解析/提取HTML文档。 DOM库通常存在于每种编程语言中。

如果您要提取不匹配正则符合的字符串的部分,则可以简单地替换 与一个空字符串匹配以达到相同的效果。

请注意,这可能起作用的唯一原因是因为您有兴趣删除的标签, <script><style> 标签,不能嵌套。

但是,这并不少见 <script> 标记以包含代码以编程性附加另一个 <script> 标签,在这种情况下,您的正则是失败的。在任何标签未正确关闭的情况下,它也会失败。

您不能用正则表达式解析HTML。

用正则表达式解析HTML导致悲伤。

我知道您只是为了娱乐而做,但是那里的包裹比实际解析正确的方法,并可以可靠地进行测试。

不要重新发明轮子,而是这样做几乎可以保证使您沮丧的方式。

供您参考,

而不是与jQuery相比,可以从HTML标记中单独提取文本。为此,您可以使用以下模式。

$("<div/>").html("#elementId").text()

你可以参考这个 JSFIDDLE

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top