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

<p>
<a href="foo">

但不是这些:

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

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

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

我相信上面写着:

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

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


当前回答

RegEx匹配除XHTML自包含标记之外的开放标记跳过所有其他标记(和内容)。


这个正则表达式就是这样做的。如果您只需要匹配特定的Open标记,请列出一个列表替换(?:p | br |<whatever tags you want>)并替换[\w:]+构造在下面的适当位置。

<(?:(?::(?):(script | style | object | embed | applet | noframes | noscript | noembed)(?:\s+(?>“[\s\s]*?”|'[\s\s]*?'|(?:?\s*>)[\s\s]*</\1\s*(?=>)(*跳过)(*失败))|(?:[\w:]+\b(?=((?:“[\s\s]*?”|'[\s\s]*?'|[^>]?)*)>)\2(?<!/))|/?)|\?[\S\S]*?\|(?:

https://regex101.com/r/uMvJn0/1

 # Mix html/xml     
 # https://regex101.com/r/uMvJn0/1     
 
 <
 (?:
    
    # Invisible content gets failed
    
    (?:
       (?:
                               # Invisible content; end tag req'd
          (                    # (1 start)
             script
           | style
           | object
           | embed
           | applet
           | noframes
           | noscript
           | noembed 
          )                    # (1 end)
          (?:
             \s+ 
             (?>
                " [\S\s]*? "
              | ' [\S\s]*? '
              | (?:
                   (?! /> )
                   [^>] 
                )?
             )+
          )?
          \s* >
       )
       
       [\S\s]*? </ \1 \s* 
       (?= > )
       (*SKIP)(*FAIL)
    )
    
  | 
    
    # This is any open html tag we will match
    
    (?:
       [\w:]+ \b 
       (?=
          (                    # (2 start)
             (?:
                " [\S\s]*? " 
              | ' [\S\s]*? ' 
              | [^>]? 
             )*
          )                    # (2 end)
          >
       )
       \2 
       (?<! / )
    )
    
  | 
    # All other tags get failed
    
    (?:
       (?: /? [\w:]+ \s* /? )
     | (?:
          [\w:]+ 
          \s+ 
          (?:
             " [\S\s]*? " 
           | ' [\S\s]*? ' 
           | [^>]? 
          )+
          \s* /?
       )
     | \? [\S\s]*? \?
     | (?:
          !
          (?:
             (?: DOCTYPE [\S\s]*? )
           | (?: \[CDATA\[ [\S\s]*? \]\] )
           | (?: -- [\S\s]*? -- )
           | (?: ATTLIST [\S\s]*? )
           | (?: ENTITY [\S\s]*? )
           | (?: ELEMENT [\S\s]*? )
          )
       )
    )
    (*SKIP)(*FAIL)
 )
 >

其他回答

Try:

<([^\s]+)(\s[^>]*?)?(?<!/)>

它与您的类似,但最后一个>不能在斜杠之后,也接受h1。

下面是XML/XTML的PCRE正则表达式,它是根据简化的EBNF语法定义构建的:

/
(?(DEFINE)
(?<tag> (?&tagempty) | (?&tagopen) ((?&textnode) | (?&tag) | (?&comment))* (?&tagclose))
(?<tagunnested> (?&tagempty) | (?&tagopen) ((?&textnode) | (?&comment))* (?&tagclose))
(?<textnode> [^<>]+)
(?<comment> <!--([\s\S]*?)-->)
(?<tagopen> < (?&tagname) (?&attrlist)? (?&ws)* >)
(?<tagempty> < (?&tagname) (?&ws)* (?&attrlist)? (?&ws)* \/>)
(?<tagclose> <\/ (?&tagname) (?&ws)* >)
(?<attrlist> ((?&ws)+ (?&attr))+)
(?<attr> (?&attrunquoted) | (?&attrsinglequoted) | (?&attrdoublequoted) | (?&attrempty))
(?<attrempty> (?&attrname))
(?<attrunquoted> (?&attrname) (?&ws)* = (?&ws)* (?&attrunquotedvalue))
(?<attrsinglequoted> (?&attrname) (?&ws)* = (?&ws)* ' (?&attrsinglequotedvalue) ')
(?<attrdoublequoted> (?&attrname) (?&ws)* = (?&ws)* " (?&attrdoublequotedvalue) ")
(?<tagname> (?&alphabets) ((?&alphabets) | (?&digits))*)
(?<attrname>(?&alphabets)+((?&alphabets)|(?&digits)|[:-]) )
(?<attrunquotedvalue> [^\s"'=<>`]+)
(?<attrsinglequotedvalue> [^']+)
(?<attrdoublequotedvalue> [^"]+)
(?<alphabets> [a-zA-Z])
(?<digits> [0-9])
(?<ws> \s)
)
(?&tagopen)
/x

这说明了如何为上下文无关语法构建正则表达式。您可以通过将最后一行的匹配从(?&tagopen)更改为例如(?&tagunnested)来匹配定义的其他部分

真正的问题是:你应该这样做吗?

对于XML/XTML,共识是否定的!

感谢尼基奇提供了这个想法。

在shell中,可以使用sed解析HTML:

图灵.sed编写HTML解析器(作业)???利润


相关(为什么不应该使用正则表达式匹配):

如果你这么喜欢正则表达式,为什么不嫁给它们?正则表达式:现在有两个问题黑客攻击stackoverflow.com的HTML清理器

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

RegEx匹配除XHTML自包含标记之外的开放标记跳过所有其他标记(和内容)。


这个正则表达式就是这样做的。如果您只需要匹配特定的Open标记,请列出一个列表替换(?:p | br |<whatever tags you want>)并替换[\w:]+构造在下面的适当位置。

<(?:(?::(?):(script | style | object | embed | applet | noframes | noscript | noembed)(?:\s+(?>“[\s\s]*?”|'[\s\s]*?'|(?:?\s*>)[\s\s]*</\1\s*(?=>)(*跳过)(*失败))|(?:[\w:]+\b(?=((?:“[\s\s]*?”|'[\s\s]*?'|[^>]?)*)>)\2(?<!/))|/?)|\?[\S\S]*?\|(?:

https://regex101.com/r/uMvJn0/1

 # Mix html/xml     
 # https://regex101.com/r/uMvJn0/1     
 
 <
 (?:
    
    # Invisible content gets failed
    
    (?:
       (?:
                               # Invisible content; end tag req'd
          (                    # (1 start)
             script
           | style
           | object
           | embed
           | applet
           | noframes
           | noscript
           | noembed 
          )                    # (1 end)
          (?:
             \s+ 
             (?>
                " [\S\s]*? "
              | ' [\S\s]*? '
              | (?:
                   (?! /> )
                   [^>] 
                )?
             )+
          )?
          \s* >
       )
       
       [\S\s]*? </ \1 \s* 
       (?= > )
       (*SKIP)(*FAIL)
    )
    
  | 
    
    # This is any open html tag we will match
    
    (?:
       [\w:]+ \b 
       (?=
          (                    # (2 start)
             (?:
                " [\S\s]*? " 
              | ' [\S\s]*? ' 
              | [^>]? 
             )*
          )                    # (2 end)
          >
       )
       \2 
       (?<! / )
    )
    
  | 
    # All other tags get failed
    
    (?:
       (?: /? [\w:]+ \s* /? )
     | (?:
          [\w:]+ 
          \s+ 
          (?:
             " [\S\s]*? " 
           | ' [\S\s]*? ' 
           | [^>]? 
          )+
          \s* /?
       )
     | \? [\S\s]*? \?
     | (?:
          !
          (?:
             (?: DOCTYPE [\S\s]*? )
           | (?: \[CDATA\[ [\S\s]*? \]\] )
           | (?: -- [\S\s]*? -- )
           | (?: ATTLIST [\S\s]*? )
           | (?: ENTITY [\S\s]*? )
           | (?: ELEMENT [\S\s]*? )
          )
       )
    )
    (*SKIP)(*FAIL)
 )
 >