是否可以检查两组是否相等?

Joe*_*oeS 3 regex

如果我有这样的HTML:

 <b>1<i>2</i>3</b>
Run Code Online (Sandbox Code Playgroud)

以下正则表达式:

 \<[^\>\/]+\>(.*?)\<\/[^\>]+\>
Run Code Online (Sandbox Code Playgroud)

然后它将匹配:

 <b>1<i>2</i>
Run Code Online (Sandbox Code Playgroud)

我希望它只匹配开始和结束标记相同的HTML.有没有办法做到这一点?

谢谢,

tch*_*ist 6

有没有办法做到这一点?

是的,当然了.忽略那些轻率的非答案,告诉你它无法完成.它当然可以.您可能不希望这样做,正如我在下面解释的那样.

编号捕获

假装HTML <i><b>标签总是否定属性的nonce,而且,既不重叠也不嵌套,我们有这个简单的解决方案:

#!/usr/bin/env perl
#
# solution A: numbered captures
#
use v5.10;
while (<>) {
    say "$1: $2" while m{
          < ( [ib] ) >
          (
              (?:
                  (?!  < /? \1  > ) .
              ) *
          )
          </ \1  >
    }gsix;
}
Run Code Online (Sandbox Code Playgroud)

哪个在运行时产生这个:

$ echo 'i got <i>foo</i> and <b>bar</b> bits go here' | perl solution-A
i: foo
b: bar
Run Code Online (Sandbox Code Playgroud)

命名捕获

最好使用命名捕获,这导致了这种等效的解决方案:

#!/usr/bin/env perl
#
# Solution B: named captures
#
use v5.10;
while (<>) {
    say "$+{name}: $+{contents}" while m{      
          < (?<name> [ib] ) >
          (?<contents>
              (?:
                  (?!  < /? \k<name>  > ) .
              ) *
          )
          </ \k<name>  >
    }gsix;
}
Run Code Online (Sandbox Code Playgroud)

递归捕获

当然,假设这样的标签既不重叠也不嵌套是不合理的.由于这是递归数据,因此需要递归模式来解决.记住用于递归地解析嵌套parens的trival模式很简单:

( \( (?: [^()]++ | (?-1) )*+ \) )
Run Code Online (Sandbox Code Playgroud)

我将在前面的解决方案中构建这种递归匹配,并且我将进一步抛出一些迭代处理来解开内部位.

#!/usr/bin/perl
use v5.10;
# Solution C: recursive captures, plus bonus iteration 
while (my $line = <>) {
    my @input = ( $line );
    while (@input) { 
        my $cur = shift @input;
        while ($cur =~ m{      
                          < (?<name> [ib] ) >
                          (?<contents>
                              (?:
                                    [^<]++
                                  | (?0)
                                  | (?!  </ \k<name>  > )
                                     .
                              ) *+
                          )
                          </ \k<name>  >
               }gsix)
        {
            say "$+{name}: $+{contents}";
            push @input, $+{contents};
        } 
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个demo会产生这个:

$ echo 'i got <i>foo <i>nested</i> and <b>bar</b> bits</i> go here' | perl Solution-C
i: foo <i>nested</i> and <b>bar</b> bits
i: nested
b: bar
Run Code Online (Sandbox Code Playgroud)

这仍然相当简单,所以如果它适用于你的数据,那就去吧.

语法模式

但是,它实际上并不知道正确的HTML语法,它允许标记属性为<i><b>.

正如在这个答案中所解释的那样,当然可以使用正则表达式来解析标记语言,只要注意它.

例如,这知道与<i>(或<b>)标签密切相关的属性.在这里,我们定义了用于构建语法正则表达式的正则表达式子例程.这些只是定义,就像定义常规潜艇一样,但现在用于正则表达式:

(?(DEFINE)   # begin regex subroutine defs for grammatical regex

    (?<i_tag_end> < / i > )

    (?<i_tag_start> < i (?&attributes) > )

    (?<attributes> (?: \s* (?&one_attribute) ) *)

    (?<one_attribute>
        \b
        (?&legal_attribute)
        \s* = \s* 
        (?:
            (?&quoted_value)
          | (?&unquoted_value)
        )
    )

    (?<legal_attribute> 
          (?&standard_attribute) 
        | (?&event_attribute)
    )

    (?<standard_attribute>
          class
        | dir
        | ltr
        | id
        | lang
        | style
        | title
        | xml:lang
    )

    # NB: The white space in string literals 
    #     below DOES NOT COUNT!   It's just 
    #     there for legibility.

    (?<event_attribute>
          on click
        | on dbl   click
        | on mouse down
        | on mouse move
        | on mouse out
        | on mouse over
        | on mouse up
        | on key   down
        | on key   press
        | on key   up
    )

    (?<nv_pair>         (?&name) (?&equals) (?&value)         ) 
    (?<name>            \b (?=  \pL ) [\w\-] + (?<= \pL ) \b  )
    (?<equals>          (?&might_white)  = (?&might_white)    )
    (?<value>           (?&quoted_value) | (?&unquoted_value) )
    (?<unwhite_chunk>   (?: (?! > ) \S ) +                    )
    (?<unquoted_value>  [\w\-] *                              )
    (?<might_white>     \s *                                  )
    (?<quoted_value>
        (?<quote>   ["']      )
        (?: (?! \k<quote> ) . ) *
        \k<quote> 
    )
    (?<start_tag>  < (?&might_white) )
    (?<end_tag>          
        (?&might_white)
        (?: (?&html_end_tag) 
          | (?&xhtml_end_tag) 
         )
    )
    (?<html_end_tag>       >  )
    (?<xhtml_end_tag>    / >  )

)
Run Code Online (Sandbox Code Playgroud)

一旦你掌握了语法部分,你就可以将这些定义纳入已经给出的递归解决方案中,以便做得更好.

但是,仍然有一些事情没有被考虑过,而且在更一般的情况下必须是这样.这些已在已提供的较长解决方案中得到证明.

摘要

我只想到三个可能的原因,为什么你可能不关心使用正则表达式来解析一般HTML:

  1. 你使用的是一种贫穷的正则表达式语言,而不是现代语言,所以你必须求助于基本的现代便利,比如递归匹配或语法模式.
  2. 你可能会像递归和语法模式这样的概念过于复杂,难以理解.
  3. 你更喜欢别人为你做所有繁重的工作,包括繁重的测试,所以你宁愿使用单独的HTML解析模块而不是自己动手.

其中任何一个或多个都可能适用.在这种情况下,不要这样做.

对于简单的固定示例,这条路线很容易.你希望它能够在你以前从未见过的事物上运行得越强大,这条路线就越难.

当然,如果你使用像Python这样的语言,甚至更糟糕的Javascript,使用劣质,贫困的模式匹配,你就无法做到.那些几乎没有比Unix grep程序好,在某些方面,甚至更糟.不,你需要一个现代模式匹配引擎,如Perl或PHP中的引擎,甚至可以从这条路开始.

但老实说,让别人为你做这件事可能更容易,我的意思是你应该使用一个已经编写过的解析模块.

仍然,理解为什么不打扰这些基于正则表达式的方法(至少,不超过一次)要求您首先使用正则表达式正确实现正确的HTML解析.你需要了解它的全部意义.因此,像这样的小练习对于提高对问题空间和现代模式匹配的整体理解是有用的.


这个论坛并不是用于解释现代模式匹配所有这些事情的正确格式.然而,有些书籍表现得非常好.


归档时间:

查看次数:

2006 次

最近记录:

14 年,3 月 前