提取标签属性的正则表达式

新手上路,请多包涵

我正在尝试提取锚标记的属性( <a> )。到目前为止,我有这样的表达:

 (?<name>\b\w+\b)\s*=\s*("(?<value>[^"]*)"|'(?<value>[^']*)'|(?<value>[^"'<> \s]+)\s*)+

适用于像这样的字符串

<a href="test.html" class="xyz">

和(单引号)

 <a href='test.html' class="xyz">

但不适用于不带引号的字符串:

 <a href=test.html class=xyz>

我如何修改我的正则表达式使其与不带引号的属性一起使用?或者有更好的方法吗?

更新: 感谢到目前为止所有好的评论和建议。有一件事我没有提到:遗憾的是我不得不修补/修改不是我写的代码。而且没有时间/金钱从下到上重写这些东西。

原文由 splattne 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 686
2 个回答

2021 年更新: Radon8472评论regex101.com 正则表达式 https://regex101.com/r/tOF6eA/1

 <a[^>]*?href=(["\'])?((?:.(?!\1|>))*.?)\1?

2021 年之二更新: Dave评论 中建议考虑包含等号的属性值,例如 <img src="test.png?test=val" /> ,如 本 regex101 所示

 (\w+)=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?


更新(2020 年), Gyum Fox 提议 https://regex101.com/r/U9Yqqg/2 (再次注意 regex101.com 在我最初写这个答案时不存在)

 (\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?

应用于:

 <a href=test.html class=xyz>
<a href="test.html" class="xyz">
<a href='test.html' class="xyz">
<script type="text/javascript" defer async id="something" onload="alert('hello');"></script>
<img src="test.png">
<img src="a test.png">
<img src=test.png />
<img src=a test.png />
<img src=test.png >
<img src=a test.png >
<img src=test.png alt=crap >
<img src=a test.png alt=crap >


原始答案(2008 年):如果您有类似的元素

<name attribute=value attribute="value" attribute='value'>

此正则表达式可用于连续查找每个属性名称和值

(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?

应用于:

 <a href=test.html class=xyz>
<a href="test.html" class="xyz">
<a href='test.html' class="xyz">

它会产生:

 'href' => 'test.html'
'class' => 'xyz'

注意: 这不适用于数字属性值,例如 <div id="1"> 将不起作用。

编辑: 改进的正则表达式,用于获取没有值的属性和内部带有“’”的值。

 ([^\r\n\t\f\v= '"]+)(?:=(["'])?((?:.(?!\2?\s+(?:\S+)=|\2))+.)\2?)?

应用于:

 <script type="text/javascript" defer async id="something" onload="alert('hello');"></script>

它会产生:

 'type' => 'text/javascript'
'defer' => ''
'async' => ''
'id' => 'something'
'onload' => 'alert(\'hello\');'

原文由 VonC 发布,翻译遵循 CC BY-SA 4.0 许可协议

尽管不通过正则表达式解析 HTML 的建议是有效的,但这里有一个表达式几乎可以满足您的要求:

 /
   \G                     # start where the last match left off
   (?>                    # begin non-backtracking expression
       .*?                # *anything* until...
       <[Aa]\b            # an anchor tag
    )??                   # but look ahead to see that the rest of the expression
                          #    does not match.
    \s+                   # at least one space
    ( \p{Alpha}           # Our first capture, starting with one alpha
      \p{Alnum}*          # followed by any number of alphanumeric characters
    )                     # end capture #1
    (?: \s* = \s*         # a group starting with a '=', possibly surrounded by spaces.
        (?: (['"])        # capture a single quote character
            (.*?)         # anything else
             \2           # which ever quote character we captured before
        |   ( [^>\s'"]+ ) # any number of non-( '>', space, quote ) chars
        )                 # end group
     )?                   # attribute value was optional
/msx;

“但是等等,”你可能会说。 “*评论呢?!?!”好的,那么您可以将非回溯部分中的 . 替换为:(它还处理 CDATA 部分。)

 (?:[^<]|<[^!]|<![^-\[]|<!\[(?!CDATA)|<!\[CDATA\[.*?\]\]>|<!--(?:[^-]|-[^-])*-->)

  • 此外,如果您想在 Perl 5.10(我认为是 PCRE)下运行替换,您可以将 \K 放在属性名称之前,而不必担心捕获所有要跳过的内容。

原文由 Axeman 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题