nto*_*end 202 regex html-parsing
似乎stackoverflow上的每个问题,其中提问者使用正则表达式从HTML中获取一些信息将不可避免地有一个"答案",表示不使用正则表达式来解析HTML.
为什么不?我知道那里有引用 - 不引用"真正的"HTML解析器,比如Beautiful Soup,我相信它们是强大而有用的,但是如果你只是做一些简单,快速或肮脏的事情,那么为什么当一些正则表达式语句运行得很好时,麻烦使用如此复杂的东西?
此外,是否有一些基本的东西,我不了解正则表达式,这使得它们一般是解析的错误选择?
Joh*_*iss 207
正则表达式无法进行整个HTML解析,因为它依赖于匹配开头和结束标记,这是正则表达式无法实现的.
正则表达式只能匹配常规语言,但HTML是无上下文的语言,而不是常规语言(正如@StefanPochmann所指出的,常规语言也是无上下文的,因此无上下文并不一定意味着不规则).你可以用HTML上的regexp做的唯一的事情就是启发式,但这并不适用于所有条件.应该可以呈现一个HTML文件,该文件将被任何正则表达式错误地匹配.
kmk*_*lan 35
对于quick'n'dirty regexp会很好.但要知道的根本事情是,构建一个正确解析HTML 的正则表达式是不可能的.
原因是regexp无法处理任意嵌套表达式.请参阅可以使用正则表达式来匹配嵌套模式吗?
And*_*ter 19
(来自http://htmlparsing.com/regexes)
假设您有一个HTML文件,您尝试从<img>标记中提取URL.
<img src="http://example.com/whatever.jpg">
Run Code Online (Sandbox Code Playgroud)
所以你在Perl中写这样的正则表达式:
if ( $html =~ /<img src="(.+)"/ ) {
$url = $1;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,$url
确实会包含
http://example.com/whatever.jpg
.但是当你开始像这样开始获取HTML时会发生什么:
<img src='http://example.com/whatever.jpg'>
Run Code Online (Sandbox Code Playgroud)
要么
<img src=http://example.com/whatever.jpg>
Run Code Online (Sandbox Code Playgroud)
要么
<img border=0 src="http://example.com/whatever.jpg">
Run Code Online (Sandbox Code Playgroud)
要么
<img
src="http://example.com/whatever.jpg">
Run Code Online (Sandbox Code Playgroud)
或者你开始得到误报
<!-- // commented out
<img src="http://example.com/outdated.png">
-->
Run Code Online (Sandbox Code Playgroud)
它看起来很简单,对于一个单一的,不变的文件来说可能很简单,但对于你将要对任意HTML数据做的任何事情,正则表达式只是未来心痛的一个秘诀.
Han*_*Gay 16
两个快速的原因:
关于正则表达式一般用于解析的适用性:它们不适合.您是否见过解析大多数语言所需的各种正则表达式?
Vat*_*ine 16
就解析而言,正则表达式在"词法分析"(lexer)阶段非常有用,其中输入被分解为标记.它在实际的"构建解析树"阶段不太有用.
对于HTML解析器,我希望它只接受格式良好的HTML,并且需要正则表达式之外的功能(它们不能"计数"并确保给定数量的开放元素由相同的数字平衡关闭元素).
因为有很多方法可以"搞砸"浏览器会以相当自由的方式处理的HTML,但是需要花费很多精力来重现浏览器的自由行为来覆盖所有具有正则表达式的情况,所以你的正则表达式将不可避免地失败一些特殊的案例,这可能会在您的系统中引入严重的安全漏洞.
问题是,大多数提出与HTML和正则表达式有关的问题的用户都会这样做,因为他们无法找到有效的正则表达式.然后,我们必须考虑在使用DOM或SAX解析器或类似的东西时是否一切都会更容易.它们经过优化和构建,目的是使用类似XML的文档结构.
当然,有些问题可以通过正则表达式轻松解决.但重点在于轻松.
如果您只想查找看起来像http://.../
regexp 一样好的所有网址.但是,如果要查找具有类"mylink"的a-Element中的所有URL,则最好使用适当的解析器.
小智 5
HTML/XML 分为标记和内容。正则表达式仅在进行词法标记解析时有用。我想你可以推断出内容。对于 SAX 解析器来说,这将是一个不错的选择。标签和内容可以传递给用户定义的函数,在该函数中可以跟踪元素的嵌套/关闭。
至于只是解析标签,它可以用正则表达式完成,并用于从文档中去除标签。
经过多年的测试,我发现了浏览器解析标签的方式的秘密,无论是好的还是坏的。
普通元素用这种形式解析:
这些标签的核心使用这个正则表达式
(?:
" [\S\s]*? "
| ' [\S\s]*? '
| [^>]?
)+
Run Code Online (Sandbox Code Playgroud)
您会注意到这[^>]?
是其中一种变化。这将匹配来自格式错误的标签的不平衡引号。
它也是正则表达式最邪恶的根源。它的使用方式将触发一次碰撞以满足它贪婪的、必须匹配的量化容器。
如果被动使用,则永远不会有问题但是,如果您通过将某些东西与所需的属性/值对穿插来强制匹配,并且没有提供足够的防止回溯的保护,那将是一场失控的噩梦。
这是普通旧标签的一般形式。注意到 [\w:]
代表标签名称了吗?实际上,代表标签名称的合法字符是一个令人难以置信的 Unicode 字符列表。
<
(?:
[\w:]+
\s+
(?:
" [\S\s]*? "
| ' [\S\s]*? '
| [^>]?
)+
\s* /?
)
>
Run Code Online (Sandbox Code Playgroud)
继续前进,我们还看到您无法在不解析所有标签的情况下搜索特定标签。我的意思是你可以,但它必须使用像 (*SKIP)(*FAIL) 这样的动词组合,但仍然必须解析所有标签。
原因是标签语法可能隐藏在其他标签中,等等。
因此,要被动地解析所有标签,需要像下面这样的正则表达式。这个特定的内容也匹配不可见的内容。
当新的 HTML 或 xml 或任何其他开发新结构时,只需将其添加为替代之一。
网页说明 - 我从未见过有问题的网页(或 xhtml/xml)
。如果你找到了,请告诉我。
性能说明 - 很快。这是我见过的最快的标签解析器
(可能更快,谁知道呢)。
我有几个特定的版本。它也非常适合用作刮刀
(如果您是动手型的)。
完整的原始正则表达式
<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>
格式化外观
<
(?:
(?:
(?:
# Invisible content; end tag req'd
( # (1 start)
script
| style
| object
| embed
| applet
| noframes
| noscript
| noembed
) # (1 end)
(?:
\s+
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
)?
\s* >
)
[\S\s]*? </ \1 \s*
(?= > )
)
| (?: /? [\w:]+ \s* /? )
| (?:
[\w:]+
\s+
(?:
" [\S\s]*? "
| ' [\S\s]*? '
| [^>]?
)+
\s* /?
)
| \? [\S\s]*? \?
| (?:
!
(?:
(?: DOCTYPE [\S\s]*? )
| (?: \[CDATA\[ [\S\s]*? \]\] )
| (?: -- [\S\s]*? -- )
| (?: ATTLIST [\S\s]*? )
| (?: ENTITY [\S\s]*? )
| (?: ELEMENT [\S\s]*? )
)
)
)
>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
58767 次 |
最近记录: |