正则表达式选取标签之间的所有文本

202

如何选择两个标签之间的所有文本-例如:页面上所有“<pre>”标签之间的文本。


2
最好的方法是使用像“Beautiful Soup”这样的HTML解析器,如果你喜欢Python的话... - Fredrik Pihl
1
最好的方法是使用XML/HTML解析器。 - Daniel O'Hara
4
通常情况下,使用正则表达式解析HTML并不是一个好主意:https://dev59.com/X3I-5IYBdhLWcg3wq6do。 - murgatroid99
不要使用正则表达式解析标签之间的文本,因为任意嵌套的标签会使HTML变得不规则。匹配标签似乎是可以的。/<div>.*?<\/div>/.exec("<div><div></div></div>") - jdh8
<div\s+id="HEADER">(.|\n)*?</div>$ - Vishal Sinha
23个回答

209
您可以使用"<pre>(.*?)</pre>",(将pre替换为您想要的任何文本),并提取第一组(如需更具体的说明,请指定语言),但这假设您有非常简单和有效的HTML。
正如其他评论者建议的那样,如果您正在处理复杂的内容,请使用HTML解析器。

84
这并不是选择标签之间的文本,它包含了标签本身。 - capikaw
3
你需要使用 () 抓取所选内容。 - Vishal Kumar Sahu
6
对于多行标签:<html_tag>(.+)((\s)+(.+))+</html_tag> - Felipe Augusto
4
如果你在尝试使用<pre>(.*?)<\/pre>后仍然看到<pre>标签,那是因为你正在查看完全匹配(full match)捕获的内容,而不是(.*?)捕获组的内容。听起来有点俗套,但我总是认为“括号=一对小偷”,因为除非(后面跟着一个?,例如(?:(?>,否则每个匹配都会有两个捕获:一个用于完全匹配(full match),一个用于捕获组。每增加一组括号就会增加一个额外的捕获组。你只需要知道如何在你所使用的语言中检索出这两个捕获组即可。 - rbsdca
1
你需要转义 / - phil123456
显示剩余3条评论

196

标签可以在另一行中完成。这就是为什么需要添加\n的原因。

<PRE>(.|\n)*?<\/PRE>

9
在处理跨越多行的HTML标签时,添加(.|\n)*?是一个重要的要点。所选答案仅在HTML标签在同一行上时有效。 - Caleuanhopkins
7
好的,我会尽力以最简洁和准确的方式翻译以下内容:<PRE>(.|\n|\r\n)*?</PRE> 适用于 Windows 换行符。 - Mark
7
永远不要使用 (.|\n)*? 来匹配任何字符,而应该使用带有 s (单行模式) 修饰符的 .。或者可以使用 [\s\S]*? 来解决。 - Wiktor Stribiżew
我想在Notepad++中选择代码注释,因此使用这个答案,我得到了 /\*(.|\n)*?\*/ 这个正则表达式,它完成了工作 - 谢谢。 - wkille

51
为了排除分隔标签:
(?<=<pre>)(.*?)(?=</pre>)

(?<=<pre>) 查找 <pre> 后面的文本

(?=</pre>) 查找 </pre> 前面的文本

结果将会是 pre 标签内的文本。


请查看@krishna thakor的答案,如果内容在标签之间有新行,则也可以考虑该答案。 - KingKongCoder
这对我的情况有所帮助(不需要考虑换行符)。谢谢。 - Pking
2
如果你有多个元素,这种方法不起作用。例如:<pre>first</pre><pre>second</pre> - Evan Kleiner

42

这是我会使用的方法。

(?<=(<pre>))(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|`~]| )+?(?=(</pre>))

基本上它所做的是:

(?<=(<pre>)) 选择必须以<pre>标签开头。

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| ) 这只是我想应用的一个正则表达式��在这种情况下,它选择字母、数字、换行符或方括号中列出的一些特殊字符。管道字符|表示"或"。

+? 加号字符表示要选择以上内容中的一个或多个 - 顺序不重要。问号将默认行为从“贪婪”改为“非贪婪”。

(?=(</pre>)) 选择必须以</pre>标签结尾。

图片描述

根据您的用例,您可能需要添加一些修改器,例如(im)

  • i - 不区分大小写
  • m - 多行搜索

在这里,我在Sublime Text中执行了此搜索,因此不必在我的正则表达式中使用修改器。

Javascript不支持向后查找

上述示例应该在诸如PHP、Perl、Java等语言中很好地工作。
然而,Javascript不支持向后查找,所以我们必须忘记使用`(?))`并寻找一些解决方法。也许可以简单地从结果中剥离每个选择的前4个字符,就像这里: https://dev59.com/_Wgu5IYBdhLWcg3wFDNr

还要查看JAVASCRIPT REGEX DOCUMENTATION了解非捕获括号


请注意,您需要使用 ` 转义单/双引号字符,以便将正则表达式放入字符串中。 - David Zwart

26

这个答案假设支持向前/向后查找!这使我能够识别出在一对开放和关闭标签之间的所有文本。也就是在'>'和'<'之间的所有文本。它有效的原因是向前/向后查找不会消耗匹配的字符。

(?<=>)([\w\s]+)(?=<\/)

我在https://regex101.com/上使用此HTML片段进行了测试。

<table>
<tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td></tr>
<tr><td>Cell 4</td><td>Cell 5</td><td>Cell 6</td></tr>
</table>

这是一个由三部分组成的游戏:回顾过去、内容本身和展望未来。

(?<=>)    # look behind (but don't consume/capture) for a '>'
([\w\s]+) # capture/consume any combination of alpha/numeric/whitespace
(?=<\/)   # look ahead  (but don't consume/capture) for a '</'

screen capture from regex101.com

我希望这可以作为一个好的起点,祝你好运。

4
谢谢。这不仅是一个更好的答案,还提供了一个指向regex101网站的好链接。点赞! - Sean Feldman
上面的正则表达式已经很好了,但它只会返回第一个匹配项,并且不包括特殊字符和换行符。为此,请改用以下代码:myString.match(/(?<=>)([\w\s\-\!@#$%^&*()_+|~={}[]:";'?,./]+)(?=</)/gm);`。这将返回一个包含所有匹配项的数组,包括几乎所有可用的特殊字符。 - Raphael Setin
@RaphaelSetin,我们可以使用(?<=>)([^>]*) (?=</)代替单个的大正则表达式组合来匹配文本中的所有单词、空格和特殊字符。 - Vijayakumar
@Vijayakumar,我不是正则表达式的专家,所以我的解决方案并不那么高级哈哈。如果你的解决方案可行,那就更好了。但是我认为其中一个缺点是我不知道你的解决方案到底包含了哪些特殊字符。你至少应该提及一下。 - Raphael Setin

25
使用以下模式以获取元素之间的内容。将 [tag] 替换为您希望从中提取内容的实际元素。
<[tag]>(.+?)</[tag]>

有时标签会带有属性,比如锚标签(anchor)的href, 然后使用下面的模式。

 <[tag][^>]*>(.+?)</[tag]>

尝试第一个例子,使用'<head>(.+?)</head>',效果如预期。但是我在第二个例子中没有任何结果。 - Alex Byrth
1
这个不起作用。<[tag]>将匹配<t><a><g> - Martin Schneider
8
@MA-Maddin - 我认为你漏掉了“用实际元素替换[tag]以提取所需内容”的部分。 - LWC
4
好的,没问题。这些[]应该完全省略掉才更清晰,因为它们在正则表达式中有特殊含义,并且人们通常会先浏览代码再阅读文本 ;) - Martin Schneider

12

这似乎是我发现的所有最简单的正则表达式

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. 从匹配结果中排除开头标签 (?:<TAG>)
  2. 将任何空格或非空格字符([\s\S]*)包括在匹配结果中
  3. 从匹配结果中排除结束标签 (?:<\/TAG>)

2
谢谢。在这个之前,我试了所有的方法才找到一个适合我的解决方案。我需要一个可以从HTML文件中抓取SCSS的正则表达式,即style[lang="scss"]的innerHTML,而这个链接帮了我大忙:https://regex101.com/r/VqhNsI/1。 - Cody
1
只有这个适用于我(JavaScript)。 - kiwichris

9
您不应该尝试使用正则表达式解析HTML,请参考这个问题以及它的解答。

简单来说,HTML不是一个正则语言,因此您无法完全使用正则表达式解析它。

尽管如此,当没有类似标签嵌套时,您可以解析HTML的子集。所以只要在<tag></tag>之间的任何内容不是该标签本身,这种方法就可行:

preg_match("/<([\w]+)[^>]*>(.*?)<\/\1>/", $subject, $matches);
$matches = array ( [0] => full matched string [1] => tag name [2] => tag content )

更好的方法是使用解析器,如本机的DOMDocument,加载您的html,然后选择您的标签并获取内部html,可能看起来像这样:
$obj = new DOMDocument();
$obj -> load($html);
$obj -> getElementByTagName('el');
$value = $obj -> nodeValue();

由于这是一个适当的解析器,因此它将能够处理嵌套标记等。


2
我只想说,我有点不安,因为尽管这是唯一一个除了正则表达式之外提供适当解决方案的答案,而且我还充分警告它可能不是正确的方法,但它仍在收集反对票。请至少评论一下我的回答有什么问题,谢谢。 - sg3s
1
该问题未标记为“php”。不确定PHP是如何出现在图片中的... - trincot
@trincot 这已经是7年前的事了,所以我记不清了。无论如何,这是一个使用正则表达式和解析器解决问题的示例。正则表达式很好,而PHP只是当时我熟悉的语言。 - sg3s
我明白了,我看到了你的第一条评论,认为这可能可以解释一些负评。 - trincot
在Python中,"/<([\w]+)[^>]>(.?)</\1>/"无法匹配。 - CS QGB

5

试试这个....

(?<=\<any_tag\>)(\s*.*\s*)(?=\<\/any_tag\>)

3
注意,JavaScript 不支持 Lookbehind(向后查找)。 - allicarn
当然,但这个正则表达式是为Java设计的。感谢您的留言。 - Heriberto Rivera

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接