我需要匹配所有这些开头标记:

<p>
<a href="foo">

但不是这些:

<br />
<hr class="foo" />

我想出了这个,想确保我做得对。我只是在捕捉a-z。

<([a-z]+) *[^/]*?>

我相信上面写着:

找到一个小于,然后查找(并捕获)a-z一次或多次,然后找到零个或多个空格,然后查找任何字符零次或多次,贪婪,除了/,然后查找大于

我有这个权利吗?更重要的是,你怎么看?


当前回答

这可能会:

<.*?[^/]>

或不带结束标记:

<[^/].*?[^/]>

HTML解析器上的火焰大战是怎么回事?HTML解析器必须解析(并重建!)整个文档,然后才能对搜索进行分类。在某些情况下,正则表达式可能更快/更优雅。我的2美分。。。

其他回答

我建议在PHP中使用QueryPath解析XML和HTML。它的语法与jQuery基本相同,只是在服务器端。

我想这可能有用

<[a-z][^<>]*(?:(?:[^/]\s*)|(?:\s*[^/]))>

这可以在这里进行测试。


根据W3学校。。。

XML命名规则

XML元素必须遵循以下命名规则:

名称可以包含字母、数字和其他字符名称不能以数字或标点字符开头名称不能以字母xml(或xml、xml等)开头名称不能包含空格可以使用任何名称,不保留任何单词。


我使用的模式将遵循这些规则。

我同意解析XML,特别是HTML的正确工具是解析器,而不是正则表达式引擎。然而,正如其他人所指出的,有时使用正则表达式更快、更容易,并且如果您知道数据格式,就可以完成任务。

微软实际上有一节《.NET Framework中正则表达式的最佳实践》,专门讨论了“考虑输入源”。

正则表达式确实有局限性,但您是否考虑过以下问题?

在正则表达式方面,.NET框架是独一无二的,因为它支持平衡组定义。

请参见将平衡构造与.NET正则表达式匹配请参见.NET正则表达式:Regex和平衡匹配请参阅Microsoft关于平衡组定义的文档

因此,我相信您可以使用正则表达式解析XML。然而,请注意,它必须是有效的XML(浏览器对HTML非常宽容,并且允许HTML中有错误的XML语法)。这是可能的,因为“平衡组定义”将允许正则表达式引擎充当PDA。

引用上述第1条:

.NET正则表达式引擎如上所述,不能用正则表达式。但是,.NET正则表达式引擎提供了一些允许平衡构造辨识。(?<group>)-使用名称组。(?<-group>)-从捕获堆栈。(?(组)yes|no)-如果存在组,则匹配yes部分否则,名称组不匹配任何部分。这些构造允许.NET正则表达式模拟通过本质上允许简单版本的堆栈来限制PDA操作:推送、弹出和清空。简单的操作非常简单分别相当于递增、递减和比较为零。这允许.NET正则表达式引擎识别上下文无关语言的子集,特别是那些仅需要一个简单的计数器。这反过来允许非传统的.NET正则表达式,以识别各个正确平衡的构造。

考虑以下正则表达式:

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

使用标志:

单线IgnorePatternHitespace(如果折叠正则表达式并删除所有空格,则不需要)IgnoreCase(不需要)

正则表达式解释(内联)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

您可以在一个更好的.NET正则表达式测试仪上尝试。

我使用了以下示例源:

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

这找到了匹配项:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

尽管它实际上是这样的:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

最后,我真的很喜欢杰夫·阿特伍德的文章:解析Html的Cthhulhu方式。有趣的是,它引用了这个问题的答案,目前有超过4万张选票。

尽管为此目的使用正则表达式并不合适和有效,但有时正则表达式为简单的匹配问题提供了快速解决方案,在我看来,将正则表达式用于琐碎的工作并不可怕。

有一篇关于匹配StevenLevithan编写的最内部HTML元素的权威博客文章。

我喜欢用正则表达式解析HTML。我不会试图解析故意破坏的白痴HTML。这段代码是我的主解析器(Perl版):

$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

它被称为htmlsplit,将HTML拆分为多行,每行上有一个标记或文本块。然后可以使用其他文本工具和脚本(如grep、sed、Perl等)进一步处理这些行。

如果您希望处理巨大的网页,将我的slurp一切第一个Perl脚本重新设置为一个不错的流式处理就足够简单了。但这不是真的必要。

HTML拆分


一些更好的正则表达式:

/(<.*?>|[^<]+)\s*/g    # Get tags and text
/(\w+)="(.*?)"/g       # Get attibutes

它们适用于XML/XTML。

通过小的变化,它可以处理杂乱的HTML。。。或者先转换HTML->XHTML。


编写正则表达式的最佳方式是使用Lex/Yacc样式,而不是不透明的单行或注释的多行怪物。我还没有在这里这样做;这些人几乎不需要它。