似乎在stackoverflow上的每个问题中,提问者使用regex从HTML中获取一些信息,将不可避免地有一个“答案”,说不要使用regex解析HTML。
为什么不呢?我知道有一些所谓的“真正的”HTML解析器,比如Beautiful Soup,我相信它们是强大而有用的,但如果您只是在做一些简单、快速或简单的事情,那么当一些正则表达式语句就可以很好地工作时,为什么要麻烦使用如此复杂的东西呢?
此外,是否只是因为我不理解正则表达式的某些基本原理,才使得它们在解析中成为一个糟糕的选择?
似乎在stackoverflow上的每个问题中,提问者使用regex从HTML中获取一些信息,将不可避免地有一个“答案”,说不要使用regex解析HTML。
为什么不呢?我知道有一些所谓的“真正的”HTML解析器,比如Beautiful Soup,我相信它们是强大而有用的,但如果您只是在做一些简单、快速或简单的事情,那么当一些正则表达式语句就可以很好地工作时,为什么要麻烦使用如此复杂的东西呢?
此外,是否只是因为我不理解正则表达式的某些基本原理,才使得它们在解析中成为一个糟糕的选择?
当前回答
正则表达式对于HTML这样的语言来说还不够强大。当然,有一些例子可以使用正则表达式。但通常不适合进行解析。
其他回答
正则表达式对于HTML这样的语言来说还不够强大。当然,有一些例子可以使用正则表达式。但通常不适合进行解析。
You, know...there's a lot of mentality of you CAN'T do it and I think that everyone on both sides of the fence are right and wrong. You CAN do it, but it takes a little more processing than just running one regex against it. Take this (I wrote this inside of an hour) as an example. It assumes the HTML is completely valid, but depending on what language you're using to apply the aforementioned regex, you could do some fixing of the HTML to make sure that it will succeed. For example, removing closing tags that are not supposed to be there: </img> for example. Then, add the closing single HTML forward slash to elements that are missing them, etc.
我将在编写一个库的上下文中使用它,该库允许我执行类似于JavaScript的[x]. getelementsbytagname()的HTML元素检索。我只是拼接了我在正则表达式的DEFINE部分中编写的功能,并使用它来进入元素树,一次一个。
那么,这将是验证HTML的最终100%答案吗?不。但这只是个开始,只要再努力一点,就可以做到。然而,试图在一个正则表达式执行中完成它是不实际的,也不有效。
(来自http://htmlparsing.com/regexes)
假设您有一个HTML文件,您试图从中提取url < img >标签。
<img src="http://example.com/whatever.jpg">
所以你可以用Perl写一个这样的正则表达式:
if ( $html =~ /<img src="(.+)"/ ) {
$url = $1;
}
在本例中,$url确实包含 http://example.com/whatever.jpg。但是当 你会得到这样的HTML:
<img src='http://example.com/whatever.jpg'>
or
<img src=http://example.com/whatever.jpg>
or
<img border=0 src="http://example.com/whatever.jpg">
or
<img
src="http://example.com/whatever.jpg">
否则你就会得到假阳性
<!-- // commented out
<img src="http://example.com/outdated.png">
-->
它看起来很简单,对于一个单一的、不变的文件来说可能很简单,但是对于任意HTML数据,正则表达式只会让你将来头疼。
我也试着用正则表达式来做这个。它主要用于查找与下一个HTML标记配对的内容块,它不查找匹配的结束标记,但它将拾取结束标记。用你自己的语言滚动一堆来检查这些。
与“sx”选项一起使用。如果你觉得幸运的话,也可以加上g:
(?P<content>.*?) # Content up to next tag
(?P<markup> # Entire tag
<!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
<!--(?P<comment>.+?)-->| # <!-- Comment -->
</\s*(?P<close_tag>\w+)\s*>| # </tag>
<(?P<tag>\w+) # <tag ...
(?P<attributes>
(?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
(?P<attribute_name>\w+)
(?:\s*=\s*
(?P<attribute_value>
[\w:/.\-]+| # Unquoted
(?=(?P<_v> # Quoted
(?P<_q>['\"]).*?(?<!\\)(?P=_q)))
(?P=_v)
))?
# </snip>
)*
)\s*
(?P<is_self_closing>/?) # Self-closing indicator
>) # End of tag
这个是为Python设计的(它可能适用于其他语言,还没有尝试过,它使用了正的反向查找头,负的反向查找头和命名的反向引用)。支持:
打开标签- <div…> 关闭标签- </div> 评论- <!——……--> Cdata - <![CDATA[…]] > 自关闭标签- <div…/> 可选属性值- <input checked> 未加引号/加引号的属性值- <div style='…'> 单引号/双引号- <div style="…" > 转义引号- <a title='John\'s Story'> (这不是真正有效的HTML,但我是一个好人) 等号周围的空格- <a href = '…'> 命名捕获感兴趣的位
它还可以很好地避免在格式错误的标记上触发,比如当您忘记了<或>时。
如果你的regex支持重复命名捕获,那么你是黄金,但Python re不支持(我知道regex支持,但我需要使用香草Python)。以下是你得到的结果:
content - All of the content up to the next tag. You could leave this out. markup - The entire tag with everything in it. comment - If it's a comment, the comment contents. cdata - If it's a <![CDATA[...]]>, the CDATA contents. close_tag - If it's a close tag (</div>), the tag name. tag - If it's an open tag (<div>), the tag name. attributes - All attributes inside the tag. Use this to get all attributes if you don't get repeated groups. attribute - Repeated, each attribute. attribute_name - Repeated, each attribute name. attribute_value - Repeated, each attribute value. This includes the quotes if it was quoted. is_self_closing - This is / if it's a self-closing tag, otherwise nothing. _q and _v - Ignore these; they're used internally for backreferences.
如果您的正则表达式引擎不支持重复的命名捕获,则可以使用一个被调用的部分来获取每个属性。只需在属性组上运行该正则表达式,从中获得每个属性、attribute_name和attribute_value。
演示在这里:https://regex101.com/r/mH8jSu/11
两个简单的原因:
编写一个能够抵御恶意输入的正则表达式是困难的;比使用预先构建的工具难多了 编写一个正则表达式来处理你不可避免地会遇到的荒谬的标记是困难的;比使用预先构建的工具难多了
关于正则表达式在解析中的适用性:它们并不合适。您是否见过解析大多数语言所需的正则表达式类型?