(如果你不耐烦,只需跳到底部的摘要部分)
这是commonly expressed here on Stack Overflow并且在开发者中 试图用正则表达式解析HTML的社区(" regexes")是一个 馊主意。引用Jeff Atwood of Coding Horror:
所以,虽然我可能尝试使用正则表达式in certain situations解析HTML,但我知道:
- 这通常是一个坏主意。
- 除非你有纪律,并且对你所做的事情有非常严格的条件 做,匹配HTML与正则表达式迅速陷入疯狂, 就是Cthulhu喜欢它的方式。
- 我有我认为是好的,理性的,(半)可辩护的理由 在这个特定场景中选择正则表达式。
其中一些原因似乎属于这些类别:
You can't use it to parse arbitrary HTML,因为有 已知cases where a regular expression wouldn't work。
正则表达式无法正确处理无效的HTML(这只是一个例子 上面#1?)。
HTML is a "Chomsky Type 2 grammar (context free grammar)",而 正则表达式是" Chomsky Type 3语法(常规语法)"。
然而,人们也提到在某些情况下,it's okay to parse a limited set of known HTML:
[我]有时适合解析一组有限的已知HTML。
我认为这就是 错误的,因为要求每个简单的HTML处理任务都要由a来处理 完整的解析引擎。了解这些工具更重要,并且 他们的优点和缺点,而不是膝盖反射 教条主义。
我从未理解它在哪种情况下适当的"解析HTML 使用正则表达式,如上面两个引用所示。我猜是因为我没有 真正了解正则表达式真正起作用的情况:
显然,当HTML甚至无效时,正则表达式不起作用,是 右
如果您的输入HTML始终有效,该怎么办?解析是否可以 它与正则表达式呢?
是的,我已经看过this Stack Overflow question with examples already了。 不,答案真的没有帮助...... this one, in particular, lacks explanation。
我现在提出这个问题因为我一直在阅读一些来源 Ruby ERB和jQuery的代码,他们使用正则表达式进行解析 HTML字符串! 那么为什么他们使用正则表达式而不是HTML解析器呢?为什么 在这些情况下,正则表达式不会导致某种不正确的行为吗?
所以这里the source code from ERB that's using regex to parse templates:
def scan_line(line)
line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
tokens.each do |token|
next if token.empty?
yield(token)
end
end
end
我已使用下面的代码测试了这一点,果然,scan_line
正确地标记模板,解析HTML和ERB标记:
t = <<TEMPLATE
<div>
<% cupcakes.each do |c| %>
<p>Oh boy, another cupcake!</p>
<ul>
<li>Flavor: <%= c.flavor %></li>
<li>Price: <%= c.price %></li>
</ul>
<% end %>
</div>
TEMPLATE
t.split("\n").each do |line|
scan_line(line) { |token| puts token }
end
这会产生以下输出:
<div>
<%
cupcakes.each do |c|
%>
<p>Oh boy, another cupcake!</p>
<ul>
<li>Flavor:
<%=
c.flavor
%>
</li>
<li>Price:
<%=
c.price
%>
</li>
</ul>
<%
end
%>
</div>
此处the regex in jQuery's source code:
define(function() {
// Match a standalone tag
return (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
});
我已经在浏览器控制台中对此进行了测试,看起来它只会匹配 纯HTML标记,即没有属性和文本内容的标记。例如:
/^<(\w+)\s*\/?>(?:<\/\1>|)$/.exec('<p>Hello!</p>');
// null
/^<(\w+)\s*\/?>(?:<\/\1>|)$/.exec('<img src="foo.jpg"/>');
// null
/^<(\w+)\s*\/?>(?:<\/\1>|)$/.exec('<img/>');
// ["<img/>", "img"]
/^<(\w+)\s*\/?>(?:<\/\1>|)$/.exec('<img>');
// ["<img/>", "img"]
/^<(\w+)\s*\/?>(?:<\/\1>|)$/.exec('<div></div>')
// ["<div></div>", "div"]
上面的Ruby ERB和jQuery源代码使用正则表达式来解析HTML字符串! 那么为什么他们使用正则表达式而不是HTML解析器呢?为什么 在这些情况下,正则表达式不会导致某种不正确的行为吗?
如果您可以期望输入HTML始终有效,那么可以解析它 与正则表达式?
答案 0 :(得分:2)
正如Casper在评论中所说,ERB正在使用自己的解析规则处理自己的语言,而不是HTML,所以这是一个红色的鲱鱼。同样,你给出的例子中的jQuery并不是试图解析一般HTML,只是它的一小部分。
在某些情况下,使用正则表达式是合适的。如果您可以丢弃所有关于HTML的语法和结构的知识并将输入视为简单的文本文件,那么正则表达式可以正常工作。
要考虑的另一件事是错误的后果。如果您尝试使用大量随机HTML文件进行说明,例如,采样目的,您将得到一些误报和一些假阴性匹配。但是,如果大多数潜在的匹配是正确的,那么可以为您提供足够精确度所需的输出。
这让我们回到了jQuery。示例代码正在处理的HTMLish字符串仅由jQuery使用。所以这场比赛将会奏效或失败。如果失败,那么客户端代码的开发人员就会明白,因为它不会做开发人员打算做的事情。这同样适用于一般HTML。 HTML的作者将在浏览器中进行测试,浏览器使用解析器而非正则表达式,并确定它在该上下文中执行作者所需的操作。如果您的代码以不同的方式处理它,您将承担所有误报和漏报的风险。
要简要说明您的最终问题,有效性无关紧要。
顺便说一句,我怀疑一个完整的html解析引擎比一个完整的正则表达式引擎更复杂。只是有时一个正则表达式引擎更接近手。
另一点。这里值得考虑社会背景。通常我们会看到人们出现在Stack Overflow上,说“我正在尝试用我的正则表达式处理一些HTML,它不起作用而且我被卡住了,我该如何解决?”你被卡住的事实是一个很大的线索,你应该使用解析器。
答案 1 :(得分:2)
基于我们上面的讨论回答:
ERB没有解析HTML。它正在解析ERB。那里有很大的不同。
ERB看起来在结构上与HTML类似,为什么它不同? - 蛋糕
我认为你可能会将模式匹配与解析混淆。当您需要快速执行简单任务时,模式匹配简单的HTML构造通常是正常的。大多数示例都更多地涉及模式匹配类别。但解析是另一回事。
解析意味着通过利用词汇和上下文分析来构建某种预定义语言的连贯数据结构。当你谈到使用正则表达式解析HTML时,这通常被理解为你想要做的事情。
这是一个非常复杂的过程,因为HTML很复杂。 ERB并不复杂,ERB很简单。因此ERB可以被解析&#34;只使用简单的模式匹配规则。这就是区别。
答案 2 :(得分:0)
我想主要的论点是DOM或HTML解析只能通过有效的 DOM或HTML输入和无错误的DOM / HTML解析器库来完成。我希望特别是jQuery必须处理这些问题。
答案 3 :(得分:0)
ERb绝对没有任何关于HTML的内容。 ERb库解析ERb,而不是HTML。 ERb专门设计用于解析Ruby的Regexp
s。
如果ERb使用HTML解析器,那么它如何解析database.yml
,这是YAML,而不是HTML?它如何解析.js.erb
,这是ECMAScript,而不是HTML?