【发布时间】:2011-11-03 03:27:18
【问题描述】:
如何使用正则表达式检索 html sn-p 中的所有 html 标签名称?如果重要的话,我正在使用 PHP 来执行此操作。例如:
<div id="someid">
<img src="someurl" />
<br />
<p>some content</p>
</div>
应该返回:div、img、br、p。
【问题讨论】:
如何使用正则表达式检索 html sn-p 中的所有 html 标签名称?如果重要的话,我正在使用 PHP 来执行此操作。例如:
<div id="someid">
<img src="someurl" />
<br />
<p>some content</p>
</div>
应该返回:div、img、br、p。
【问题讨论】:
这应该适用于大多数格式良好的标记,前提是您不在 CDATA 部分并且没有玩过重新定义实体的讨厌游戏:
# nasty, ugly, illegible, unmaintable — NEVER USE THIS STYLE!!!!
/<\w+(?:\s+\w+=(?:\S+|(['"])(?:(?!\1).)*?\1))*\s*\/?>/s
或者更清晰的,如
# broken out into related elements grouped by whitespace via /x
/ < \w+ (?: \s+ \w+ = (?: \S+ | (['"]) (?: (?! \1) . ) *? \1 )) * \s* \/? > /xs
甚至更清晰:
/
# start of tag, with named ident
< \w+
# now with unlimited k=v pairs
# where k is \w+
# and v is either \S+ or else quoted
(?: \s+ \w+ = (?: \S+ # either an unquoted value,
| ( ['"] ) # or else first pick either quote
(?:
(?! \1) . # anything that isn't our quote, including brackets
) * ? # maximal should probably work here
\1 # till we see it again
)
) * # as many k=v pairs as we can find
\s * # tolerate closing whitespace
\/ ? # XHTML style close tag
> # finally done
/xs
您可以在此处添加一些草率,例如在我没有超出的几个地方容忍空白。
PHP 不一定是此类工作的最佳语言,尽管您可以在紧要关头凑合。最起码,您应该将这些东西隐藏在某个函数和/或变量中,而不是让它像裸露的一样暴露在外,考虑到 The Children Are Watching™。
要做任何比找到字母或空格更复杂的事情,模式从 cmets 和空格中受益匪浅。这是不言而喻的,但由于某种原因,人们忘记使用/x 进行认知分块,让空白对相关的事物进行分组,就像使用命令式代码一样。
即使它们是声明性程序而不是命令性程序,模式也可以从完整的问题分解和自上而下的设计中受益。实现这一点的一种方法是拥有“正则表达式子例程”您与使用它们的地方分开声明。否则你只是在做剪切和粘贴代码重用,这是悲观排序的代码重用。这是一个匹配<img> 标签的示例模式,这次使用的是真正的 Perl:
my $img_rx = qr{
# save capture in $+{TAG} variable
(?<TAG> (?&image_tag) )
# remainder is pure declaration
(?(DEFINE)
(?<image_tag>
(?&start_tag)
(?&might_white)
(?&attributes)
(?&might_white)
(?&end_tag)
)
(?<attributes>
(?:
(?&might_white)
(?&one_attribute)
) *
)
(?<one_attribute>
\b
(?&legal_attribute)
(?&might_white) = (?&might_white)
(?:
(?"ed_value)
| (?&unquoted_value)
)
)
(?<legal_attribute>
(?: (?&required_attribute)
| (?&optional_attribute)
| (?&standard_attribute)
| (?&event_attribute)
# for LEGAL parse only, comment out next line
| (?&illegal_attribute)
)
)
(?<illegal_attribute> \b \w+ \b )
(?<required_attribute>
alt
| src
)
(?<optional_attribute>
(?&permitted_attribute)
| (?&deprecated_attribute)
)
# NB: The white space in string literals
# below DOES NOT COUNT! It's just
# there for legibility.
(?<permitted_attribute>
height
| is map
| long desc
| use map
| width
)
(?<deprecated_attribute>
align
| border
| hspace
| vspace
)
(?<standard_attribute>
class
| dir
| id
| style
| title
| xml:lang
)
(?<event_attribute>
on abort
| on click
| on dbl click
| on mouse down
| on mouse out
| on key down
| on key press
| on key up
)
(?<unquoted_value>
(?&unwhite_chunk)
)
(?<quoted_value>
(?<quote> ["'] )
(?: (?! \k<quote> ) . ) *
\k<quote>
)
(?<unwhite_chunk>
(?:
# (?! [<>'"] )
(?! > )
\S
) +
)
(?<might_white> \s * )
(?<start_tag>
< (?&might_white)
img
\b
)
(?<end_tag>
(?&html_end_tag)
| (?&xhtml_end_tag)
)
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
)
}six;
是的,它会变长,但随着变长,它变得更易于维护,而不是更少。 它也更正确。 现在,使用它的实际程序不仅仅如此,因为您必须考虑比实际 HTML 更多的内容,例如 CDATA 和编码和顽皮的实体重新定义。然而,与流行的看法相反,你可以实际上用 PHP 做那种事情,因为它使用 PCRE,它允许 (?(DEFINE)...) 块和递归模式。在我的回答here、here、here、here 和here 中有更严肃的这类事情的例子。
好的,很好,您是否阅读了所有这些内容,或者至少看了一眼?还在我这儿?你好??不要忘记呼吸。在那里,你现在会没事的。 :)
当然,有一个很大的灰色区域,在那里,可能的事情让位于不明智的事情,而且比它屈服于不可能的事情要快得多。如果这些答案中的这些示例,更不用说当前答案中的这些示例,超出了您自己当前的模式匹配技能水平,那么您可能应该使用其他东西,这通常意味着让其他人为您做这件事。
【讨论】:
(?(DEFINE)...)。你知道它是否只是 Perl 和 PCRE,还是有其他支持它的实现? (我没有从 Google 获得任何有用的信息。)
正则表达式可能并不总是有效。如果您 100% 确定它是格式良好的 XHTML,那么正则表达式可能是一种方法。如果没有,请使用某种 PHP 库来执行此操作。在 C# 中,有一个叫做 HTML Agility Pack 的东西,http://htmlagilitypack.codeplex.com,例如见How do I parse HTML using regular expressions in C#?。也许PHP中有一个等效的工具。
【讨论】:
vi 中一直使用/color="#000000" 和:g/<(a|href)/p 之类的东西:你有什么问题吗?我当然希望没有!如果你对此没有问题,那么你不应该告诉人们他们不能在 HTML 上使用模式匹配,因为这不仅明显不真实,而且你说一套做一套也是虚伪的。
我想这应该可行...我会在一分钟内尝试:
编辑: 删除 \s+(感谢 Peteris)
preg_match_all('/<(\w+)[^>]*>/', $html, $matched_elements);
【讨论】:
<p>。修复是'/<(\w+)(>|\s+[^>]*>)/'。
<img src="foo.jpg" label="<what>"/> 上无法正常工作。
vi 中使用搜索和替换。如果允许,那么当然应该允许您在 HTML 上使用模式匹配。如果您不被允许,那么您不应该被允许在这些文件上使用vi。 HTML 是文本——复杂的文本,我承认,但仍然只是文本。在vi 中写:/<table>/, /<\/table>/s/<td>/<td color="#000000">/ 没有任何问题,因此用您选择的编程语言编写等价的也没有错。停止在非文本解决方案上推新手。
在 python 中,一种解决方案是使用正则表达式在 html 中获取所有不同的标签名称。
import re
s = """<div id="someid">
<img src="someurl" />
<br />
<p>some content</p>
</div>
"""
print(set(re.findall('<(\w+)', s)))
# {'p', 'img', 'div', 'br'}
or
print({i.replace('<', '') for i in re.findall('(<\w+)',s)})
# {'p', 'img', 'div', 'br'}
【讨论】: